Compare commits

...

354 Commits

Author SHA1 Message Date
ShyPike
c237ddfef4 Update text files for 0.7.9 2013-01-06 20:11:33 +01:00
ShyPike
b543dcb5ac Fix text in dropdowns being hard to see in chrome. 2013-01-06 19:33:31 +01:00
ShyPike
ccfbb07333 Take servers that only support ARTICLE into account.
When only full articles are available, the decoder needs to scan more lines
to find the start of the payload.
2013-01-06 19:33:19 +01:00
ShyPike
256ccbd6a1 Prevent crash in decoder.py 2013-01-06 19:06:15 +01:00
ShyPike
d8d507f110 Update text files for 0.7.8 2013-01-03 19:24:27 +01:00
ShyPike
7b3309649f Cancel encryption detection if meta-data if NZB contains password. 2013-01-03 18:44:31 +01:00
shypike
9a7a6652e8 Update text files for 0.7.8 2013-01-03 18:41:50 +01:00
shypike
db4891748f Update copyright year. 2013-01-03 18:40:49 +01:00
ShyPike
3dce2e8908 Support NZB 1.1 meta data; currently "category" and "password" are used.
"category" will trigger category conversion.
"password" value(s) will be used when an encrypted download is encountered.
The latter will also suppress the on-the-fly encryption detection.
2013-01-02 23:05:15 +01:00
ShyPike
c91291c315 Don't retry an empty but correct NZB retrieved from an indexer.
Also add special option "warn_empty_nzb" to control warning about empty NZBs.
2013-01-02 19:37:49 +01:00
shypike
a2a5a1f8e4 Make sure "Abort" error message ends up in download report. 2013-01-01 22:04:24 +01:00
shypike
7651f709ad API functions "addfile" and "addlocalfile" now support "nzbname" parameter for ZIP files with single NZB.
Also, prevent crash on calling "cat_convert" in those api functions (undefined).
2012-12-31 14:11:09 +01:00
shypike
a565077348 Update translations 2012-12-31 12:27:13 +01:00
shypike
6cf99e7d3a Add handling of an extra par2 error message. 2012-12-30 15:06:35 +01:00
shypike
f730a82005 Check for IPv6 connectivity should not use specific exceptions. 2012-12-30 13:16:46 +01:00
ShyPike
5449607c1d Update POT file. 2012-12-28 14:12:36 +01:00
ShyPike
c62415abfd Add "Abort" option to encryption detection.
The option pause_on_pwrar gets an extra value (2) which will
abort an encrypted job. Retrying the job will disable the check.
2012-12-28 14:10:53 +01:00
ShyPike
dcbea3057c Register removed articles and list in download report. 2012-12-28 13:23:34 +01:00
ShyPike
91642d16c8 Update POT file. 2012-12-27 22:26:33 +01:00
ShyPike
2f2773149d Fix missing Retry link for "Out of retention" jobs. 2012-12-27 22:26:05 +01:00
ShyPike
adaba03f50 Option to terminate download if too much data is missing.
Option 'fail_hopeless' Config->Switches.
On-the-fly check for possible completion after each file is processed.
Abort if it's no longer possible to download at least 99% of total data (payload + par2).
Don't do the check when retrying from History.
2012-12-27 21:56:00 +01:00
shypike
58a5e09540 Prevent web-watchdog from crashing when using Python 2.5 2012-12-27 11:28:06 +01:00
shypike
20dc906095 Support servers that don't support STAT and BODY commands.
When server sends error 500, use alternative "HEADER" and "ARTICLE" instead,
which are less efficient.
2012-12-24 20:12:01 +01:00
shypike
e2f41d3761 Add special "wait_for_dfolder", will wait for "temp download folder" at startup.
At startup, wait for the temporary download folder to come on line.
Supports situations where external drives are used, which do not mount before
SABnzbd starts up.
2012-12-23 12:11:18 +01:00
ShyPike
ab1372c7fc Prevent crash in DateSorter. 2012-12-20 18:46:45 +01:00
ShyPike
e305678cf4 In Sorting the %fn substitution sometimes fails to rename the file properly.
The Sorting code assumed that the file name used as the source for %fn
is always a base name. Sometimes it can be a full name. Deal with it.
2012-12-19 21:51:00 +01:00
ShyPike
a82df9bf2e Update text files for 0.7.7 2012-12-14 20:47:59 +01:00
ShyPike
986604f27c Update feedparser.py to from 5.1 to 5.1.3 2012-12-14 19:04:50 +01:00
shypike
59324c7453 Remove "Indexers" support page from the Wizard. 2012-12-09 13:03:03 +01:00
shypike
91613a5b37 Remove "Indexers" page from all skins. 2012-12-09 12:28:02 +01:00
shypike
5ca05fd2c0 OSX: remove association with "rar" and "zip" files. 2012-12-08 14:44:54 +01:00
shypike
4d4045cff4 Update translations 2012-12-05 21:27:04 +01:00
ShyPike
1f209a42d8 Filter unusable folders from lists generated by pathbrowser. 2012-12-03 21:13:13 +01:00
shypike
bffbb362db Update POT file. 2012-12-01 10:53:05 +01:00
shypike
435eed8818 Add 'B' to download totals on main page. 2012-12-01 10:48:27 +01:00
shypike
f86656543a Add schedule: when schedule has no days, assume daily instead of ignoring. 2012-12-01 10:06:11 +01:00
ShyPike
9c510c6dd1 When re-evaluating RSS feed, the original sort order was not preserved.
When re-using RSS entries from memory, use the original feed order and not
Python's random dictionary order.
2012-11-30 20:48:03 +01:00
ShyPike
f81ab3d1c0 Prevent crash when nzbxxx.com's category cannot be determined. 2012-11-30 18:47:38 +01:00
ShyPike
d1585c28a9 Remove all visible features for newzbin. 2012-11-29 22:07:45 +01:00
ShyPike
9c314532c0 Add optional web-watchdog to the watchdog. 2012-11-29 21:47:14 +01:00
ShyPike
853bda5d86 Add 'B' to server amounts. 2012-11-28 21:18:02 +01:00
ShyPike
d05e31f7f0 Remove placeholder for Cleanup filter in Config->General. Confusing for users. 2012-11-28 20:49:16 +01:00
ShyPike
383354871d Generic sort didn't always rename media files in multi-part jobs properly.
`rename_similar()` should be called outside of the media rename loop.
`rar_extract_core` should always return full paths.
2012-11-26 22:10:48 +01:00
ShyPike
2086a217e0 Don't use SFV check when more par2 files can still be downloaded. 2012-11-24 22:38:04 +01:00
ShyPike
34f3574746 Update unrar for Windows to 4.20 2012-11-24 21:50:14 +01:00
ShyPike
1dfe0b957e Catch a renaming bug in par2-tbb and retry with par2-classic. 2012-11-24 21:33:58 +01:00
shypike
17d14bc3b4 OSX: update unrar to version 4.20 2012-11-24 21:33:36 +01:00
ShyPike
885032e436 Improve handling of orphaned jobs.
Re-queue of a set without a nzb.gz file would not recognize par2 sets.
Convert "None" strings in the attrib file to None.
2012-11-24 21:21:06 +01:00
ShyPike
ceee95aaf7 Orphan re-queue and delete failed when path contains non-plain ASCII characters.
Convert UTF-8 name coming from CherryPy to a platform compatible name.
2012-11-24 20:38:29 +01:00
ShyPike
bc6b3091eb Update text files for 0.7.6Final. 2012-11-17 14:01:38 +01:00
ShyPike
4be1a13316 Add the "User-Agent" header of each API call to logging and warnings. 2012-11-17 10:56:36 +01:00
ShyPike
a77327ee7f Support NZB re-queuing also for NZB files in sub-folders. 2012-11-15 22:01:41 +01:00
ShyPike
aa706012af Update text files for 0.7.6Beta2 2012-11-14 21:01:01 +01:00
ShyPike
f5b6203194 Make check for running SABnzbd instance more robust.
Cancel bad side-effect of removing the version check.
Under some circumstances SABnzbd can draw the unjustified conclusion
that another instance is running. Now check for a proper version pattern
in the received output.
2012-11-14 20:57:02 +01:00
ShyPike
1ced9a54e4 Fix evaluation of schedules at startup.
With the introduction of multiple-day schedules, the schedule evaluator failed.
Fixed the evaluation.
A side-effect is that Config->Scheduler will no longer show the schedules in
the order they will occur from now. Instead they will be shown in order of
occurrence from Monday to Sunday.
2012-11-14 20:23:40 +01:00
ShyPike
06c7089a77 Correct indentation in interface.py 2012-11-13 20:59:50 +01:00
ShyPike
ee1d864eea Update text files for 0.7.6Beta2 2012-11-12 21:47:19 +01:00
ShyPike
d703338935 Repair failed when mini-par2 file was in NZB but did not result in a file.
An incomplete mini-par2 file is now skipped in favor of the next available vol-par2 file.
A missing or damaged par2 file must make the next par2 file the primary par2-file
in the next repair run.
2012-11-12 21:10:27 +01:00
ShyPike
e87b24c460 Update text files for 0.7.6Beta1 2012-11-09 19:30:29 +01:00
shypike
3404ef6516 Update translations 2012-11-09 19:23:04 +01:00
shypike
181897e92b Prevent the Decoder from choking the Assembler.
Because the Decoder is CPU-bound, it has no reason to relinquish control.
This will choke the Assembler which cannot write finished and cached articles
to the designated file. The result is an increasing cache, which either grows
indefinitely or until the Decoder must flush articles.
By simply adding a sleep(0.001), the Decoder will trigger the task-scheduler
after each article, giving the Assembler a chance to do its work.
2012-11-08 23:12:15 +01:00
ShyPike
26a504e3e2 Prepare code for intro of zoned access to UI and API. 2012-11-07 21:41:04 +01:00
ShyPike
b72ed09011 Prevent IPv6 Usenet servers from being tried when they're not reachable.
Detect whether external IPv6 addresses are reachable.
If so, allow IPv6 IPs to be picked.
Add a special option 'ipv6_servers' to allow the user to forbid (0), allow (1) or force (2)
the use of IPv6. Value 2 can be used in case the detection by SABnzbd doesn't work reliable.
2012-11-07 20:07:25 +01:00
ShyPike
bb99c0d58e Fix problem with late detection of win32api absence. 2012-11-06 23:40:45 +01:00
ShyPike
4516027fdb Repair side-effect of SFV improvements.
A download without par2 files and without SFV files should not be failed.
2012-11-05 22:51:51 +01:00
ShyPike
e35f2ea3cd Prevent crash on Unix-Pythons that don't have the os.getloadavg() function.
Some Unix Pythons are defective in not providing os.getloadavg().
Add simple exception handler to cover this case.
2012-11-05 20:40:21 +01:00
ShyPike
6b79fad626 Remove version check when looking for a running instance of SABnzbd.
This will lower the chance of inadvertently launching multiple instances.
User will need to use --new to force a new instance.
2012-11-05 19:19:32 +01:00
ShyPike
ac311be430 Successfully pre-checked job lost its attributes when those were changed during check.
For successful jobs, the attributes were not saved to disk (they were for failed ones).
Solution is to save attributes independent of result.
2012-11-05 19:09:10 +01:00
shypike
4fb32bff5f Fix crash when a job is sent to postprocessing immediaterly after startup.
The Assembler wasn't running when job was sent to post processing at
the startup of the queue. The Assembler is used as a relay to send
a job to post-processing.
Solution is to start Assembler before initializing the queue.
2012-11-05 18:54:15 +01:00
ShyPike
5fda342a55 Don't try to repair/verify par sets that have "sample" in their names.
Only when sample deletion is enabled.
2012-11-03 20:34:17 +01:00
ShyPike
e23aab4710 Improve SFV handling, preventing odd side-effects in multi-set NZBs.
SFV verification per PAR-set using only the matching SFV file.
When no par2 files are found, use all available SFV files.
Remember the verification status of each set in the "verified" marker file.
Improve par-set matcher, so that there's no mix-up when one set name
is a substring of another set name.
2012-11-03 16:57:32 +01:00
ShyPike
3837d5dace Handle par-sets that have been renamed after generation of the par2 files.
Requires a wildcard to be added as a par2 parameter to make it scan all applicable files.
The rename actions need to be stored in a persistent file to prevent re-downloading in a Retry.
The status of correct sets must be remembered while fetching extra par file for failed sets.
2012-11-03 16:56:53 +01:00
shypike
f61e7cb1ed Update text files for 0.7.5 Final. 2012-11-03 16:15:22 +01:00
ShyPike
3de0c0e4ac Add missing "%dn" (original folder name) formula to Generic Sorting. 2012-11-01 21:24:51 +01:00
ShyPike
63796d3feb Improve logging for RSS readouts. 2012-11-01 19:47:48 +01:00
ShyPike
6b07529300 Update text files for 0.7.5RC1 2012-10-30 20:35:57 +01:00
ShyPike
e10676710c Support for news in Config. 2012-10-30 20:17:51 +01:00
shypike
77f67c6666 Merge pull request #59 from akuiraz/newzxxx2_fix
Fixed regex for newzbin rss filtering
2012-10-30 11:58:20 -07:00
ShyPike
bdbcdd61e1 Mask password in "Add Server" dialog. 2012-10-30 19:51:12 +01:00
ShyPike
4ab7ec754d Add periodic detection of completed but hanging jobs in the queue.
The 30 second watchdog now detects jobs without pending files.
Those jobs will be sent to the post-processor.
2012-10-30 18:47:18 +01:00
akuiraz
20f98f48bc Fixed regex for newzbin filtering by adding xxx2, now rss feeds from newzxxx2.ch will successfully download 2012-10-30 01:27:36 -04:00
shypike
84e0502e50 Prevent crash when trying to open non-existing "complete" folder from Windows System-tray icon. 2012-10-28 12:39:34 +01:00
shypike
2aa1b00dbb Prevent CherryPy crash when reading a cookie from another app which has a non-standard name. 2012-10-27 13:33:33 +02:00
ShyPike
972078a514 Fix problem with "Read" button when RSS feed name contains "&".
The feed's name wasn't properly encoded in the URL.
2012-10-24 19:34:45 +02:00
shypike
be8382d25b Add special option 'empty_postproc'.
Setting this option will run the user script on an empty download.
Normally this isn't done.
The status sent to the user script is -1, meaning "no files were downloaded".
2012-10-21 18:23:25 +02:00
shypike
8d46e88cd8 Update translations 2012-10-21 12:56:00 +02:00
shypike
6b6b1b79ad Add 'prio_sort_list' special.
This is a list of file name extensions.
Matching files will be the first to be downloaded within an NZB.

Also, if the user sets a simple space-seperated list, this will be converted to a standardized list.
2012-10-21 12:16:13 +02:00
shypike
e1fd40b34d OSX: Retina compatible menu-bar icons. 2012-10-20 19:57:11 +02:00
ShyPike
bc1f8f97a8 Prefix categories of nzbxxx.com with "XXX:". 2012-10-20 16:03:09 +02:00
shypike
b51705f458 Fix issues with accented and special characters in names of downloaded files.
name_extractor() returned Unicode instead of platform-compatible encoding.
QuickCheck assumed incorrectly that file names are not yet platform-compatible.
2012-10-20 15:11:08 +02:00
ShyPike
aaed5f4797 Adjust nzbmatrix category table. 2012-10-17 21:30:22 +02:00
ShyPike
a8eedef1d2 Prevent stuck jobs at end of pre-check. 2012-10-17 21:22:36 +02:00
shypike
9407e21e1e Prevent unusual SFV files from crashing post-processing. 2012-10-13 10:56:05 +02:00
ShyPike
ba6dcfd467 Don't show speed and ETA when download is paused during post-processing. 2012-10-08 21:21:15 +02:00
shypike
e2c1de5008 Prevent soft-crash when api-function "addfile" is called without parameters. 2012-10-06 21:57:48 +02:00
ShyPike
10b7403748 Update text files for 0.7.4 Final. 2012-10-02 20:04:03 +02:00
ShyPike
1ba924cc12 Pre-queue script didn't get the show/season/episode information any longer.
Due to earlier changes in tvsort, the pre-queue script handler now needs to
call an extra method of the SeriesSorter.
2012-10-02 19:56:47 +02:00
ShyPike
11eb034bd3 Prevent crash on startup when a fully downloaded job is still in download queue.
When at startup, there's a job in the download which has no more file to download,
it will be passed to post-processing. However the queue logic will try do disconnect
all servers first. This call will fail because the downloader hasn't start yet.
2012-10-02 19:34:21 +02:00
ShyPike
c3250e15cb Update text files for 0.7.4 Final. 2012-10-01 21:25:19 +02:00
shypike
8ff8a59b4c Update translations 2012-10-01 21:02:44 +02:00
ShyPike
0c646d88b2 New RSS feed should no longer be considered new after first, but empty readout.
Search and bookmark feeds can be empty when entered into SABnzbd.
The "don't download first batch" rule should be discarded when the
first readout is empty (as expected).
Currently the feed remains "new" until the first content is found.
2012-10-01 19:53:22 +02:00
ShyPike
05670ea599 Make "auth" call backward-compatible with 0.6.x releases.
Return "apikey" when no key is sent, instead of "badkey".
2012-09-30 23:17:05 +02:00
ShyPike
e25eb32885 Config->Notifications: email and growl server addresses should not be marked as "url" type. 2012-09-30 16:08:19 +02:00
shypike
250f75f084 OSX: fix top menu queue info.
The OSX queue menu entry shows a maximum of 10 jobs.
However, the counter should show the total amount of active jobs along with
the total size of these jobs.
Instead only the contribution of the 10 visible jobs was shown.
2012-09-29 15:21:30 +02:00
ShyPike
cdd39e6777 Plush: Purge history will now use the active filter.
When selecting one of the buttons in the Purge History dialog will
now use the current filter to select jobs to be deleted.
This is more what people expect to happen.
2012-09-29 12:19:56 +02:00
ShyPike
281ed6766c Update text files for 0.7.4 RC2 2012-09-27 20:38:16 +02:00
shypike
cd78c89de1 Update translations 2012-09-27 20:37:14 +02:00
ShyPike
c6c983e8f2 Linux: add memory usage to status display and add special option to control display.
Show "Total Program size" (V) and "Resident set size" (R).
Option "show_sysload" has three values:
0 = Off
1 = Show CPU load
2 = Show CPU load + memory usage (default)
2012-09-26 20:44:18 +02:00
ShyPike
ef4d1ce54f Fix problems with timing of quota reset at end of period. 2012-09-25 22:51:36 +02:00
ShyPike
b1177f4265 Fix issue with queue and history not updating in Safari-IOS6.
Add "Cache-Control":"no-cache" header to each Ajax POST action.
2012-09-24 21:38:30 +02:00
shypike
02d373e4a6 Remove warning about Growl when user has disabled message class in Growl itself.
Growl 2.0 uses different text than 1.4.
Test is now compatible with both versions.
2012-09-24 17:31:41 +02:00
shypike
58c8608667 Pre-check didn't check all available par2 files.
Result was that any post with a missing article was rejected.
Regression error introduced when fixing stalling fetches of extra par2 files.
2012-09-23 14:35:27 +02:00
ShyPike
848110ac3e Fix transmission of Growl icon when running on Linux/Unix.
There's a bug in the GNTP library that prevents sending the icon as
a binary attribute along with the registration.
Work-around is to send an URL to an external location.
2012-09-22 14:37:21 +02:00
ShyPike
74d677cf09 Update text files for 0.7.4 RC1. 2012-09-22 10:19:15 +02:00
ShyPike
f029c4eb4f Add a default limit to API-call "history" in order to prevent over-sized output.
Some external tools query the full history repeatedly.
Add a default value for the API call "history" as a work-around.
Calls that have a start and limit parameter will work unchanged.
The default limit can be set in the Special "history_limit".
2012-09-22 10:16:31 +02:00
ShyPike
838811f085 Update text files for 0.7.4 RC1 2012-09-21 20:50:40 +02:00
ShyPike
e212ec7ca3 Remove potential stalling when fetching extra par fetches.
Assembler didn't set the "completed" flag on a finished file,
leading to potential deadlock when fetching extra par2 files.
2012-09-21 20:47:25 +02:00
ShyPike
6314a536af Windows: be less eager to run par2-classic instead of the multi-core version. 2012-09-21 20:46:43 +02:00
shypike
df33765ce0 Update translations 2012-09-21 20:39:20 +02:00
ShyPike
2524333e79 Update text files for 0.7.4 RC1 2012-09-20 21:04:42 +02:00
ShyPike
cf81e815ee Classic and Plush skins must specify their character encoding.
Some browsers get it wrong when they need to guess the encoding.
Added:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2012-09-19 20:29:26 +02:00
ShyPike
7bd7f1826c Win32: fix display of system name in startup notification message. 2012-09-19 20:00:19 +02:00
shypike
9ce7b528e3 Improved OSX DMG template. 2012-09-19 19:49:41 +02:00
shypike
db7b3cf0b5 Update translations 2012-09-18 21:52:26 +02:00
ShyPike
201b30b6c4 Fix packaging for Windows and add tar.gz for OSX again. 2012-09-18 20:47:57 +02:00
ShyPike
36a6bcd1f5 Update text files for 0.7.4 Beta3 2012-09-17 21:00:37 +02:00
shypike
20cfca5bb6 Combine OSX builds into one DMG image.
Split DMG creation off into a separate file.
`package.py` will now just build one OSX platform.
`make_dmg.py` will combine the three builds into one DMG.
2012-09-17 20:55:46 +02:00
ShyPike
63fe4b15c8 Show correct base folder for HTTPS certificate files (corrected). 2012-09-17 19:43:31 +02:00
ShyPike
aabc57a1f8 Show correct base folder for HTTPS certificate files. 2012-09-17 19:34:19 +02:00
ShyPike
9a8eca0993 Some code cleanup. 2012-09-17 19:16:22 +02:00
ShyPike
f8723d7e52 Prevent potential crash due to missing attribute in NzfObject. 2012-09-14 22:10:03 +02:00
ShyPike
59bb5528ed Ignore new schedule without days instead of crashing on it. 2012-09-14 21:46:36 +02:00
ShyPike
247c10692a Put "missing ssl support" warning in Wizard page One too. 2012-09-10 22:09:40 +02:00
shypike
63bed3c127 Update text files for 0.7.4Beta2 2012-09-10 19:27:58 +02:00
shypike
ca96743bad Update translations 2012-09-10 19:07:53 +02:00
shypike
525fb4de61 Update POT file, for new texts. 2012-09-10 19:06:54 +02:00
shypike
f294084dbc Build three separate DMG files for OSX.
Lion and MountainLion use the most recent native Python.
Leopard/SnowLeopard uses ActiveState Python 2.6.3.
Use a separate template for each OS version.
2012-09-09 22:19:10 +02:00
shypike
ca1327a9ae Improve handling of badly formatted subject lines in NZBs.
The NZB parser overwrote the subject even when there was no proper filename extracted.
This compromized recognition of par2 files after a first failed verification run.
Improve ability to extract a proper file name so that sorting and displaying is better.
The extraction still won't work for every malformed subject, but at least the par2 recognition should always work now.
2012-09-09 14:49:30 +02:00
shypike
dcb1b0b3dc Improve startup notification.
- Move hostname() from misc.py to growler.py.
- Improve startup notification
2012-09-08 21:00:28 +02:00
shypike
ec4b613498 Modify growler.py for new GNTP module. Fix transmission of icon.
- use 'localhost' for local Growl instead of "None".
- Sending binary icon now works properly, so external icon not needed any more.
- No need to send icon with every message, only when registering.
- Log more info about gntp-error exceptions
2012-09-08 20:23:59 +02:00
shypike
c3f4eccfbc Re-apply custom patches to new GNTP.
Reduce logging verbosity for sent messages.
Convert "info" logging to "debug" logging.
Suppress 404 + "user has disabled" error (which isn't really an error).
Time-out patch no longer needed, built-in now.
2012-09-08 20:18:13 +02:00
shypike
1aafe25a83 Update GNTP module.
Version 0.8 from github.
2012-09-08 19:52:46 +02:00
shypike
cc25ef0af0 Prevent filing an error message when the user has disabled message classes in Growl-preferences.
Problem is in the GNTP library, while at the same time it is very odd that Growl sends an error response for this.
2012-09-08 15:45:17 +02:00
shypike
5c221f4a14 After successful pre-check, preserve a job's spot in the queue.
Previously a pre-checked job re-entered at the end of the queue.
Moved the quality check from the post-processor to nzbqueue, so a successful job doesn't need to go through the post-processor.
Improvement: all other ways for a job to be sent to post-processing need to go through the end_job() method.
2012-09-08 15:01:14 +02:00
shypike
03221fc645 Config skin: "check new releases" setting did not work properly. 2012-09-08 09:46:40 +02:00
ShyPike
febf81e597 Update text files for 0.7.4Beta1 2012-09-06 21:53:52 +02:00
shypike
447ec55822 OSX: create one build for ML and one for others.
Also remove 64bit code from binaries.
2012-09-06 21:51:12 +02:00
ShyPike
eee1f49c4a Fix translation of notification classes in Config->Notification. 2012-09-05 20:00:33 +02:00
shypike
140b903783 Update translations 2012-09-05 19:43:57 +02:00
ShyPike
8361bc9f3a A job with priority "forced" should keep that when fetching more par2 files.
It was now set to "repair" priority, which doesn't ignore paused state.
Other priorities will still be promoted to "repair".
2012-09-04 19:10:13 +02:00
ShyPike
744290c228 Log failed attempts to login to the Web UI. 2012-09-03 23:18:08 +02:00
ShyPike
20768df430 Remove leak of SQLite database handles.
The non-UI threads need to close the db handles after using.
Move the unnecessary proxy for the database sizes for the bpsmeter.
2012-09-03 22:35:41 +02:00
ShyPike
7ec7e8d432 Allow compression of more MIME type in API-calls. 2012-09-03 19:30:29 +02:00
shypike
7b657a85ba Update POT files. 2012-09-01 13:23:04 +02:00
ShyPike
258699f1db Add scheduled task "Remove failed jobs". 2012-09-01 12:43:33 +02:00
Lucas Parry
0412f45323 Make scheduler more flexible
Schedules can now be set for any arbitrary group of days of the week.
2012-09-01 12:09:11 +02:00
shypike
997eb93cd9 Don't do an SFV-based verification when the job is already marked as verified.
When retrying a job that has passed succesful verification, the par2 files will already have been removed. When doing an SFV-based verification, this may lead to errors because the PAR2 files are gone. So when the "__verified__" flag-file is present and there's no par2-set, skip the SFV check.
2012-09-01 11:42:41 +02:00
shypike
b94192486b Add special option "overwrite_files".
This will overwrite existing files in the "complete" folders.
Useful for effective in "Single folder" mode and "Season Sorting".
2012-08-29 22:08:07 +02:00
shypike
73bdd2c5bf Prevent error and pause when last file of a removed job happens to be written to (and fails). 2012-08-25 12:49:07 +02:00
shypike
56e9b54cd9 Add parameter "pp_active" to the "qstatus" api call, showing state of Postprocessing. 2012-08-25 11:13:51 +02:00
shypike
3308074f81 Don't also show job in post-processing queue while fetching more par2 files. 2012-08-23 22:24:46 +02:00
shypike
c2305034a1 Handle unexpected missing par2 file in par2-check properly. 2012-08-23 20:06:44 +02:00
shypike
d77b22be37 Add support for HTTPS chain certificate file.
Just enabling the user to specify the file and then passing it on to CherryPy.
2012-08-18 14:51:21 +02:00
ShyPike
9717912ff7 When a numeric option has no value, it should be set to the default and not to the minimum value. 2012-08-16 13:47:29 +02:00
ShyPike
cfa79c08b2 When retrying post processing don't attempt to download existing par2 files again. 2012-08-16 12:10:48 +02:00
ShyPike
4f65f87ad6 Fix syntax of command used in server test. 2012-08-16 11:37:57 +02:00
shypike
aea0d21fd2 Log the output of the PAR2 command.
This will help diagnosing repair trouble that users might have.
2012-08-15 19:17:43 +02:00
shypike
ba77b43364 Default for Growl is off when on MountainLion. 2012-08-15 18:36:41 +02:00
shypike
7727eb58a8 Sort 'Done' list on RSS page in reverse time order (latest first). 2012-08-15 18:31:16 +02:00
shypike
dbd2e3f54b Make list of RSS sites that use weird titles a "Special" option, "misc, rss_odd_titles". 2012-08-15 18:13:41 +02:00
shypike
7ac6e07576 Update translatable texts 2012-08-14 20:42:34 +02:00
shypike
24ffd90fb4 sleepless.keep_awake() call needs a Unicode argument 2012-08-14 20:37:57 +02:00
shypike
011b680337 Fix path for OSX-Leopard build 2012-08-11 17:18:22 +02:00
shypike
5328e07a93 OSX: add notifier package and licencse files to DMG. 2012-08-11 14:37:37 +02:00
shypike
2d07af7cc8 Add parameter to sleepless.keep_awake() call. 2012-08-11 13:23:32 +02:00
shypike
a40d2da2ab Improve OSX Mountain Lion "stay awake" support with native OS calls.
Also add Special option "keep_awake" for Windows and OSX.
2012-08-10 22:49:41 +02:00
shypike
25ac101751 Add OSX Notification Center support.
Add option when support available on OSX ML.
Add class selection for notifications. Useful for N-Center and NtfOSD.
2012-08-09 22:55:07 +02:00
ShyPike
a666165a5e Plush: remove mailto link in Help pop-up. 2012-08-04 13:44:22 +02:00
ShyPike
e24aedc6ac Update text files for 0.7.3 Final. 2012-08-04 11:05:58 +02:00
ShyPike
d10d69e44b Correct typo in dirscanner.py. 2012-08-04 10:54:40 +02:00
ShyPike
af5c01ee3a Update Windows install size. 2012-08-03 22:58:34 +02:00
ShyPike
bf350cddc8 Update text files for 0.7.3
Fix package.py for README.mkd handling.
2012-08-03 22:28:44 +02:00
ShyPike
9bc4d909b5 Use 'pandoc' to generate README.rtf from README.mkd. 2012-08-03 21:05:08 +02:00
ShyPike
42236de5bd Update text files for 0.7.3 Final 2012-08-03 19:41:17 +02:00
ShyPike
02e2fe2cc8 Correct errors in Danish email templates. 2012-08-03 19:27:30 +02:00
ShyPike
b75bcb90f4 Server 502 message about expired subscription will now block server. 2012-08-03 19:08:21 +02:00
shypike
56b88eb406 Update translations 2012-08-03 16:01:20 +02:00
ShyPike
93741ea9ab SFV-check: don't issue a warning for each problem file, but just list in History entry. 2012-08-03 11:57:13 +02:00
ShyPike
f7509132fc Rename 'random_server_ip' to 'randomize_server_ip' and make the default 'False'.
This is to avoid confusing speed loss with some providers. Now the user has to enable this consciously.
2012-08-02 21:18:03 +02:00
ShyPike
2d0d62ec00 The "watched folder" scan should ignore all files starting with a period (hidden on Linux and OSX). 2012-08-01 00:27:23 +02:00
ShyPike
4e07a84102 Update POT files. 2012-08-01 00:25:35 +02:00
ShyPike
32a048a879 Update text files for 0.7.3 Beta2 2012-07-30 16:08:48 +02:00
shypike
caac28fcbc Try to keep OSX Mountain Lion awake as long as downloading/postprocessing runs.
Quick & Dirty solution by launching 'caffeinate' every 5 minutes.
2012-07-30 15:40:13 +02:00
ShyPike
5b0bbf57c6 Prevent queue deadlock in case of fatally damaged par2 files.
Basic problem: prevent par2 files that have already been downloaded from re-entering the queue.
The issue was introduced after removing the habit of 0.6.x to download a part of each par2 file.
The advantage of the 0.6.x method was that more was known about the par2 files,
the disadvantage that quite some data was downloaded that was never used.

Add job flag that prevents further QuickCheck attempts on known to be damaged jobs.
The method of inspecting large par2 files is time-consuming if nothing is ever found.
2012-07-30 12:41:55 +02:00
ShyPike
072af938c2 Prevent deadlock in fetching more par2 files when first par2 file is so corrupt that no info can be retrieved. 2012-07-29 14:48:27 +02:00
ShyPike
9e8202371e Add filter-enable check-boxes to Classic, Plush and smpl skinms.
Necessary because new filters created with those skins were not enabled.
2012-07-29 00:09:53 +02:00
ShyPike
27dd253c5d Fix UI crash on saving parameters of an already enabled server in Config->Servers. 2012-07-28 23:35:12 +02:00
ShyPike
8d651af2f8 Add some forward compatibility with changes coming to Scheduler in 0.8.x 2012-07-28 14:05:27 +02:00
ShyPike
6358312272 Replaced a few missed strings to be substituted with constants.Status values. 2012-07-24 21:35:03 +02:00
ShyPike
42c8367e13 Extend "check for release" with option "Also test releases". 2012-07-24 20:38:44 +02:00
ShyPike
c1e38b5e81 Update text files for 0.7.3 Beta1 2012-07-24 15:06:49 +02:00
ShyPike
1b4ce24037 Config->Servers: optimize layout 2012-07-24 11:17:40 +02:00
ShyPike
cf440750b6 Config->Servers: hide server details initially and have a simple checkbox to enable/disable servers quickly. 2012-07-24 09:14:02 +02:00
ShyPike
30c480df36 Add unofficial support for nzbmatrix's adult cousin. 2012-07-23 14:29:02 +02:00
ShyPike
9c3dbd39ef Make detection of samples less aggressive. 2012-07-22 16:35:34 +02:00
ShyPike
1af2f92828 Improve the Sort functions.
- Renaming secondary files after the main file didn't always work
- Collapsing folder structures could fail
- Joined (instead of unpacked) media files were not seen as candidates for renaming
- Presence of DVD/BRD special folders will now block collapsing
- Non-functional improvements: coding std, removed unused code and needless access functions, added doc-strings.
2012-07-22 15:43:26 +02:00
ShyPike
45277bb00f Add another keyword for canceled article detection. 2012-07-20 19:31:31 +02:00
ShyPike
10e21a3af9 Remove extra '\r' in Windows logging. 2012-07-20 19:16:35 +02:00
ShyPike
19cbadd420 Plush: fix odd formatting of multi-line warnings on Status page. 2012-07-20 19:11:52 +02:00
ShyPike
a28cbe52b9 Recovery from corrupt totals9.sab doesn't always remove bad entry. 2012-07-19 21:00:01 +02:00
shypike
37f1d64e46 Fix incorrect explanation of --no_ipv6 flag. 2012-07-18 18:00:39 +03:00
ShyPike
7170325df5 Update text files for 0.7.2 Final 2012-07-17 21:46:17 +02:00
ShyPike
c44d98da66 When localhost resolves to ['127.0.0.1', '::1'] instead of ['::1', '127.0.0.1'], SABnzbd would try to register twice on '::1'. 2012-07-17 21:29:33 +02:00
ShyPike
018410afb0 Validate the values read from totals9.sab 2012-07-17 19:38:49 +02:00
ShyPike
fc47238a7a Temporary fix for missing NZB icon when associating NZB files on a system that had a 0.7.0 release installed. 2012-07-16 18:51:39 +02:00
ShyPike
9561b8a64e Update text files for 0.7.2 RC2 2012-07-14 17:01:07 +02:00
ShyPike
7b0e56b55f Fix little anomaly in Wizard-Four. 2012-07-14 15:16:30 +02:00
ShyPike
c6d5a79776 Improve web-host address selection on systems where the hostname does not resolve to an IP address. 2012-07-14 14:27:18 +02:00
ShyPike
faa4cacd3e Improve detection of bad articles.
For now, don't let precheck use "HEAD" until method is improved.
2012-07-14 13:12:22 +02:00
ShyPike
56e417eea1 Change nzbsrus support to use their API response codes. 2012-07-14 09:40:46 +02:00
ShyPike
5f02ec00f9 Don't show nonsense NZB age when still trying to get it from an indexer. 2012-07-13 21:29:37 +02:00
ShyPike
5ea35db922 Add limited API support for nzbsrus.com 2012-07-13 21:19:09 +02:00
ShyPike
5dcf26a56c Update text files for 0.7.2RC1 2012-07-12 21:45:13 +02:00
ShyPike
35b598d10e Improve detection (and ignoring) of invalid articles.
This also requires reading headers during pre-check instead of just asking for article presence.
2012-07-12 21:24:38 +02:00
ShyPike
5e7b27c4ef Prevent potential crash in NzbQueue.repair_job() 2012-07-12 18:28:17 +02:00
ShyPike
9ed408d35b Windows Installer: don't uninstall settings by default. 2012-07-12 18:19:19 +02:00
ShyPike
6c782fe255 Fix nzbrus.com fatal error (when <nzb is not within the first 100 characters of the file). 2012-07-10 23:01:11 +02:00
ShyPike
1689323dc3 Fix sorting of files in a job so that .rar comes before .r00 again. 2012-07-10 22:12:04 +02:00
ShyPike
a3c50a907a Fix wrapping problem of queue titles in Plush skin by inserting zero-width spaces in titles. 2012-07-10 19:59:59 +02:00
ShyPike
36a3792846 After setting quota for the first time, the initial "quota left" was set to the already consumed amount of the current period, instead of the actual still available amount (which is quota-consumed). 2012-07-08 11:45:09 +02:00
ShyPike
4cd0c0691a Windows installer: fix NZB association so that a Windows reboot is not required to register the NZB icon. 2012-07-08 11:33:57 +02:00
ShyPike
6ac98dcacd Handle incorrect regular expression in RSS filters.
Ignore during scanning and signal in user interface.
2012-07-08 10:45:57 +02:00
ShyPike
0a0d00930a Update text files for 0.7.1 Final. 2012-07-06 16:50:00 +02:00
ShyPike
28a0d041f9 Correction on fix 7258e56a20.
nzf.completed is a @property attribute and should not be set directly.
2012-07-06 16:40:36 +02:00
ShyPike
85bb91a7ea Disable VC90 check in Windows Installer as long as we're still on Python 2.5 2012-07-04 21:10:49 +02:00
ShyPike
6561e0abfa Make Windows path joining of base and category paths more robust to work around different behaviors in Python and Windows versions combinations. 2012-07-04 20:36:52 +02:00
ShyPike
6715e61a68 Try to check for "maintenance" mode of nzbsrus.com 2012-07-04 19:34:00 +02:00
ShyPike
a886b284b6 Prevent "not committed" flag in baseline variable for official builds. 2012-07-04 19:09:55 +02:00
ShyPike
a349c82b6f Update text files for 0.7.1RC5 2012-07-03 21:38:20 +02:00
ShyPike
1f4df0ebf4 Only send "bad fetch" emails when emails are enabled. 2012-07-03 21:28:59 +02:00
ShyPike
0221e7bf93 Add some support for nzbsrus.com's awkward non-VIP limiting. 2012-07-03 21:14:30 +02:00
ShyPike
f9cf14e7d8 Update text files for 0.7.1 Final. 2012-07-03 19:59:36 +02:00
ShyPike
7258e56a20 When retrying a job, existing files were not flagged properly as "completed", leading to an endless loop in par2 fetching. 2012-07-03 19:58:02 +02:00
ShyPike
90bd495d44 Update text files fr 0.7.1 Final. 2012-07-03 17:54:18 +02:00
shypike
6c216d6dfe Update translations 2012-07-03 17:49:10 +02:00
ShyPike
e1f3fae6c7 Windows installer: detect incompatible older version by looking for python27.dll. 2012-07-02 22:31:28 +02:00
ShyPike
29f126ca47 Make warning about Python3 easier to read. 2012-07-02 22:13:01 +02:00
shypike
8b4b742466 Remove remaining .py files from OSX DMG image, to prevent invalid signatures after first run. 2012-07-02 18:44:36 +02:00
ShyPike
57a9d362bc Update text files for 0.7.1RC4 2012-07-01 17:26:00 +02:00
ShyPike
b7d54c2bea Fix failure to grab NZBs from indexers that send compressed files. 2012-07-01 17:23:16 +02:00
ShyPike
59f9833076 Update text files for 0.7.1 RC3 2012-07-01 14:03:59 +02:00
ShyPike
8e360fe53e Improve retry handling of URL fetches.
Add detection of error messages from nzbsrus.com and handle retries accordingly.
2012-07-01 13:49:24 +02:00
ShyPike
afc5005382 Make sure that badly formatted or otherwise incorrect articles are retried on other servers (if fail_on_crc option is on).
Make default of fail_on_crc True.
2012-07-01 13:47:55 +02:00
ShyPike
3a531c6d2b API calls "addurl" and "addid" can use the same code so that either will take newzbin IDs or regular URLs. 2012-07-01 12:53:54 +02:00
ShyPike
f056ad6347 Solve problem of stalling par2 fetching.
The attributes of the vol-par files were analyzed to late,
leading to a race condition.
2012-07-01 10:01:56 +02:00
ShyPike
5c1342a663 Tell user that Python 3.0 won't work. 2012-07-01 09:12:25 +02:00
ShyPike
dfe8a47a2a Verification/repair would not be executed properly when one more RAR files missed their first article. 2012-06-26 23:26:38 +02:00
ShyPike
e293a439dd Don't set __verified__ flag file when more par2 files need to be fetched. 2012-06-26 22:24:01 +02:00
ShyPike
7e0027922a Prevent QuickCheck crash when expected par2 file wasn't downloaded (due to missing articles). 2012-06-26 19:12:56 +02:00
shypike
00b5302ba9 Update text files for 0.7.1 Final. 2012-06-25 22:40:39 +02:00
shypike
79488c4785 Add option to suppress listening on web host address ::1 2012-06-25 22:34:07 +02:00
ShyPike
c3d0438250 Update texts for 0.7.1 RC2 2012-06-23 12:31:14 +02:00
ShyPike
2909d4636b Fix parameter bug in Swedish translation. 2012-06-23 12:28:57 +02:00
shypike
a1ee8b6af4 Update translations 2012-06-23 12:20:05 +02:00
ShyPike
cfe3b58f7f On Windows, the Python runtime starts the wrong browser when using http://::1:8080/sabnzbd. Convert URL to http://[::1]:8080/sabnzbd. 2012-06-23 12:05:38 +02:00
ShyPike
ff6b87ef5b Improve the INI file handling.
Simplify and make the save more robust.
Use the INI.BAK file when the INI file is missing or corrupt.
2012-06-21 21:46:14 +02:00
ShyPike
8fbcfd0d5a Update text files for 0.7.1RC1 2012-06-20 20:54:53 +02:00
shypike
347ba999b4 Reduce amount of info requested when updating Windows Tray icon and OSX top menu.
The Windows Tray icon queried for free diskspace, while it is never shown.
The OSX top menu should query for no more queue entries than it will show (10).
The OSX top menu queue didn't show accented characters properly.
2012-06-20 20:48:55 +02:00
ShyPike
503bcf64c9 Prevent problems on systems that don't bother to resolve "localhost". 2012-06-19 22:31:47 +02:00
ShyPike
2a667470a1 Add retries when creating "final folder" to allow for slow activation of mounted volumes. 2012-06-19 19:05:33 +02:00
ShyPike
c61165b840 Plush: fix Speedlimit, Pause and Options pulldown menus for Mobile Safari. 2012-06-18 22:17:09 +02:00
ShyPike
3672189bc8 Remove another unwanted Windows DLL when building on Windows 7. 2012-06-16 13:41:44 +02:00
ShyPike
5b38c772fb When the "uname -n" name of a system doesn't resolve to an IP, only use 0.0.0.0 as hostname when the user hadn't set "localhost", "127.0.0.1" or "::1" as the hostname.
Otherwise any such system will still listen on the external IP despite the fact that user didn't want this.
2012-06-16 12:18:12 +02:00
ShyPike
f28bc4dd9c Windows: the installer did not set an icon for NZB files (association). 2012-06-16 10:45:04 +02:00
ShyPike
e16cc49a17 Config-skin: "server" field in Config->Servers should have html5 tag "text" instead of "url". 2012-06-16 10:44:48 +02:00
ShyPike
f686cc94fd Modify server test to please very critical Usenet server. 2012-06-16 10:44:32 +02:00
ShyPike
d88b5a3b3e Restore proper support for Python 2.5 on Windows by including curl tool again. 2012-06-10 15:35:56 +02:00
shypike
bccc5665f5 Prevent Growl crash at shutdown, due to accented characters in message. 2012-06-10 15:03:56 +02:00
ShyPike
69ac9d39ad Update text files for release 0.7.0Final. 2012-06-09 10:36:31 +02:00
ShyPike
b5b6999bc9 Default value of cache_limit should remain empty. 2012-06-09 10:25:09 +02:00
shypike
7ddb3d2752 Update translations 2012-06-08 18:49:31 +02:00
ShyPike
9febaf919c Update translations. 2012-06-06 17:34:12 +02:00
shypike
2225383485 Removed gntp and gnutext as required modules, because they are included in the distribution. 2012-06-06 17:36:32 +03:00
shypike
e3e500326c Update translations 2012-06-05 19:16:06 +02:00
ShyPike
b73570fe2a Update text files for 0.7.0 RC2 2012-06-02 21:24:08 +02:00
shypike
d1357875c9 Update translations 2012-06-02 21:23:33 +02:00
ShyPike
037c7661ea Suppress permission errors on paths containing ".AppleDouble" or ".DS_Store".
Common on NAS systems that support OSX with AFP shares.
2012-06-02 21:17:13 +02:00
ShyPike
5337ade3fb Set article cache to 200M when not already set. 2012-06-02 15:57:08 +02:00
ShyPike
504ce5458f Pre-check: lower default minimum completion rate to 100.2% 2012-06-01 19:43:07 +02:00
ShyPike
d8d3b60cbc Update text files for 0.7.0 RC1 2012-05-30 21:32:02 +02:00
ShyPike
0b0e7d5531 Pre-check: the required ratio for NZBs without par2 files should be 100% and not the "safe" ratio. 2012-05-30 21:28:24 +02:00
ShyPike
18cd9ab7ca Update text files for 0.7.0 RC1 2012-05-30 20:32:17 +02:00
shypike
1392b3b1eb Update translations 2012-05-30 20:29:56 +02:00
ShyPike
cd93abfab1 Fix for rare crash in par2 fetching. 2012-05-30 20:09:16 +02:00
ShyPike
9fede00949 Fix failing nomedia marker file (again). 2012-05-27 21:10:26 +02:00
ShyPike
6ddc3fec96 Windows SystemTray menu code sometimes times out when coming out of standby/hibernate. Catch exception and hope for the best... 2012-05-27 20:53:04 +02:00
ShyPike
f1030f9b6f Quota reset wasn't done when quota-reset-time was passed while SABnzbd wasn't running.
Due to not setting self.have_quota before reading the totals9.sab file.
2012-05-27 12:46:45 +02:00
shypike
6a8ff22f96 Fix error message. 2012-05-26 09:06:31 +02:00
ShyPike
1e82b79c16 Update text files for 0.7.0 Beta8. 2012-05-25 20:26:58 +02:00
shypike
d85bc90cbb Update translations 2012-05-25 20:22:25 +02:00
ShyPike
fdce48376a Add completion rate info to email notifying about failed pre-check run. 2012-05-25 20:11:55 +02:00
ShyPike
58cc6b2e7d Rename special option "marker_file" to "nomedia_marker" and disable it by default. 2012-05-25 19:48:10 +02:00
ShyPike
5ebad3cb70 Fix signing of OSX Leopard app. 2012-05-22 20:21:47 +02:00
ShyPike
d4757a0a74 Update text files for 0.7.0 Beta7 2012-05-22 19:57:15 +02:00
shypike
0406a4b901 Update translations 2012-05-22 19:53:34 +02:00
ShyPike
95684fbe3a Do removal of ".nomedia" marker file earlier, just after unpacking. So before it can be moved by the Sorting functions.
This also solves the problem of the NZB-chaining being disabled.
2012-05-22 19:39:23 +02:00
ShyPike
a4f8155138 Prevent crash when Wizard tries to resolve the system's name to an IP (and name cannot resolve). 2012-05-22 19:09:00 +02:00
ShyPike
cddb1ba7f3 Remove junk code. 2012-05-21 18:41:39 +02:00
ShyPike
73b2930a0b Remove potential exe.log file in Windows uninstaller. 2012-05-21 18:40:48 +02:00
ShyPike
e74519ca43 When the Sort functions look to rename auxiliary files after a main file, they should ignore casing of the original names. 2012-05-20 14:09:07 +02:00
ShyPike
f75fad9c6a Add Polish to NSIS script. 2012-05-18 14:12:48 +02:00
ShyPike
2d8805a49f Spend more effort to track down and delete the .nomedia marker file at the end of post-processing. 2012-05-18 12:45:21 +02:00
ShyPike
fc3a19a816 Translatable hover-over texts for Windows Tray icon. 2012-05-18 11:31:18 +02:00
ShyPike
e1b2d49341 Update POT files. 2012-05-17 22:37:18 +02:00
ShyPike
2cb6890dac Add two Wizard texts for later Unicode release. 2012-05-17 22:36:07 +02:00
ShyPike
e6bef729ed Add some type safety to database.py (preparing for Unicode). 2012-05-17 14:26:15 +02:00
ShyPike
1545f7a4ef Handle newline idiosyncrasies of gettext for NSIS template. 2012-05-17 14:24:59 +02:00
ShyPike
3f9446a336 Update text files for 0.7.0 Beta6 2012-05-17 10:44:46 +02:00
shypike
7b3ab90a95 Update translations 2012-05-16 22:51:58 +02:00
shypike
636b264432 OSX: Make "10.1 MB/s" fit in menu bar status by omitting the space. 2012-05-16 22:30:33 +02:00
ShyPike
59fd6bf23d Lower default threshold for pre-check to 100.5% 2012-05-16 20:33:31 +02:00
ShyPike
59b4bbcdaa Don't retry bookmark removals for nzbmatrix.com.
Currently it causes a crash, but otherwise the site would be hammered.
2012-05-16 17:50:36 +02:00
ShyPike
a82bdd9f74 Always use URL when complaining about unsuccessful NZB fetches. 2012-05-15 20:10:49 +02:00
ShyPike
a4f10e7577 Prevent crash in rare case of a timeout on a connection that has just been cleared by the "unreliable-server" detection. 2012-05-15 19:32:19 +02:00
shypike
71f3231487 Update translations 2012-05-14 18:05:30 +02:00
ShyPike
2133092402 Add Polish translation (with reduced character set). 2012-05-14 17:58:08 +02:00
ShyPike
20e47ab099 Use readable substitutions for quote and apostrophe. 2012-05-13 14:27:40 +02:00
ShyPike
3e9c8c3ff8 Update INSTALL.txt 2012-05-12 23:09:55 +02:00
ShyPike
731f331502 Upgrade unzip for Windows to 6.0 2012-05-12 23:05:22 +02:00
ShyPike
b15efb4d38 Clean up package.py. 2012-05-12 23:04:08 +02:00
shypike
ccfb0df819 Remove .nomedia marker file also when it has been moved by Sorting. 2012-05-12 19:57:12 +02:00
shypike
620ef9fc64 Extension-based cleanup list should also remove extension-only files like ".sfv". 2012-05-12 19:48:59 +02:00
shypike
f799fc08f7 Remove some debugging lines. 2012-05-12 19:47:51 +02:00
ShyPike
11a1ce4a6c Set UI-ready flag sooner. 2012-05-12 16:04:04 +02:00
shypike
9610a5a0dd Do HTML quoting for " and ' characters in skin texts.
Improve skin text translation cache implementation.
2012-05-12 15:54:44 +02:00
ShyPike
0b39afcd18 Fix incorrect README.rtf. 2012-05-09 21:08:45 +02:00
ShyPike
abe53b8a8a Fix error in OSX signing. 2012-05-09 20:59:42 +02:00
ShyPike
bffdf77d9a Fix crash of Sorting preview when using accented characters in example. 2012-05-09 20:37:19 +02:00
shypike
31a7016c15 Merge pull request #37 from thezoggy/uniConfig
Integrate Config skin (previously a submodule)
2012-05-09 11:15:50 -07:00
ShyPike
b92bd6aa0d Remove submodule Config. 2012-05-09 20:12:25 +02:00
ShyPike
ed4a6567c3 Update text files for 0.7.0 Beta5 2012-05-09 20:07:15 +02:00
Jonathon Saine
1988977d7c Remove submodule and just use clone of uniConfig master branch. 2012-05-08 16:43:08 -05:00
ShyPike
9f33bb4bb3 Improve rounding of ratio in pre-check so that you don't get messages like "101.0% is less than required 101.0%". 2012-05-08 22:46:17 +02:00
shypike
02a8141de2 Create unified DMG file for all OSX versions. 2012-05-08 22:29:51 +02:00
ShyPike
c852b44dcd Update translatable texts. 2012-05-07 22:11:29 +02:00
ShyPike
1a44b38308 Add special option required completeness percentage when doing pre-check.
Set default to 101.
2012-05-07 22:11:00 +02:00
ShyPike
743bf88d28 Enable randomization of multiple Usenet server IPs by default. 2012-05-07 15:14:43 +02:00
ShyPike
c0250c2c29 Fix incorrect formatting of source URL in history. 2012-05-07 15:12:40 +02:00
shypike
50990a8a01 Fix crash in newswrapper.py when dealing with single line server responses. 2012-05-05 23:51:09 +02:00
shypike
03c12a65ac Update translations 2012-05-04 14:54:14 +02:00
ShyPike
3f7967326b Make Usenet server provider IP randomization an option instead of always on. 2012-05-04 12:08:55 +02:00
ShyPike
6d47ba30b9 Prevent exception messages being logged when evaluating incomplete Sort expressions in Config->Sorting's preview mode. 2012-05-04 10:43:12 +02:00
ShyPike
c4459e2238 Add support for ".nomedia" marker in "final" folder in order to disable scanning by media players during unpack. 2012-05-03 19:02:30 +02:00
ShyPike
cba0d3f890 Extend the Windows SysTray menu. 2012-05-01 22:15:42 +02:00
167 changed files with 22823 additions and 12352 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "interfaces/Config"]
path = interfaces/Config
url = https://github.com/thezoggy/sabnzbd-uni_Config.git

View File

@@ -1,5 +1,5 @@
*******************************************
*** This is SABnzbd 0.7.0 ***
*** This is SABnzbd 0.7.9 ***
*******************************************
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically,

View File

@@ -1,3 +1,283 @@
-------------------------------------------------------------------------------
0.7.9Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix fatal error in decoder when encountering a malformed article
- Fix compatibility with free.xsusenet.com
- Small fix in smpl-black CSS
-------------------------------------------------------------------------------
0.7.8Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix problem with %fn substitution in Sorting
- Add special "wait_for_dfolder", enables waiting for external temp download folder
- Work-around for servers that do not support STAT command
- Removed articles are now listed seperately in download report
- Add "abort" option to encryption detection
- Fix missing Retry link for "Out of retention" jobs.
- Option to abort download when it is clear that not enough data is available
- Support "nzbname" parameter in addfile/addlocalfile api calls for
ZIP files with a single NZB
- Support NZB-1.1 meta data "password" and "category"
- Don't retry an empty but correct NZB from an indexer
-------------------------------------------------------------------------------
0.7.7Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Windows/OSX: Update unrar to 4.20
- Fix some issues with orphaned items
- Generic sort didn't always rename media files in multi-part jobs properly
- Optional web-ui watchdog
- Always show RSS items in the same order as the original RSS feed
- Remove unusable folders from folder selector (Plush skin)
- Remove newzbin support
-------------------------------------------------------------------------------
0.7.6Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Recursive scanning when re-queuing downloaded NZB files
- Log "User-Agent" header of API calls
-------------------------------------------------------------------------------
0.7.6Beta2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- A damaged smallest par2 can block fetching of more par2 files
- Fix evaluation of schedules at startup
- Make check for running SABnzbd instance more robust
-------------------------------------------------------------------------------
0.7.6Beta1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Handle par2 sets that were renamed after creation
- Prevent blocking assembly of completed files, ( this resulted in
excessive CPU and memory usage)
- Fix speed issues with some Usenet servers due to unreachable IPv6 addresses
- Fix issues with SFV-base checks
- Prevent crash on Unix-Pythons that don't have the os.getloadavg() function
- Successfully pre-checked job lost its attributes when those were changed during check
- Remove version check when looking for a running instance of SABnzbd
-------------------------------------------------------------------------------
0.7.5Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Add missing %dn formula to Generic Sort
- Improve RSS logging
-------------------------------------------------------------------------------
0.7.5RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Prevent stuck jobs at end of pre-check.
- Fix issues with accented and special characters in names of downloaded files.
- Adjust nzbmatrix category table.
- Add 'prio_sort_list' special
- Add special option 'empty_postproc'.
- Prevent CherryPy crash when reading a cookie from another app which has a non-standard name.
- Prevent crash when trying to open non-existing "complete" folder from Windows System-tray icon.
- Fix problem with "Read" button when RSS feed name contains "&".
- Prevent unusual SFV files from crashing post-processing.
- OSX: Retina compatible menu-bar icons.
- Don't show speed and ETA when download is paused during post-processing
- Prevent soft-crash when api-function "addfile" is called without parameters.
- Add news channel frame
-------------------------------------------------------------------------------
0.7.4Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Pre-queue script no longer got the show/season/episode information.
- Prevent crash on startup when a fully downloaded job is still in download queue.
- New RSS feed should no longer be considered new after first, but empty readout.
- Make "auth" call backward-compatible with 0.6.x releases.
- Config->Notifications: email and growl server addresses should not be marked as "url" type.
- OSX: fix top menu queue info so that it shows total queue size
-------------------------------------------------------------------------------
0.7.4RC2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Pre-check failed to consider extra par2 files
- Fixed unjustified warning that can occur with OSX Growl 2.0
- Show memory usage on Linux systems
- Fix incorrect end-of-month quota reset
- Fix UI refresh issue when using Safari on iOS6
-------------------------------------------------------------------------------
0.7.4RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Remove potential queue stalling when downloading extra par2 files
- Make Windows version less eager to use par2-classic
- Fixed DMG images
- Add missing encoding directive to Plush and Classic skins
- Prevent oversized data in API-call "history"
-------------------------------------------------------------------------------
0.7.4Beta3 by The SABnzbd-Team
-------------------------------------------------------------------------------
- All three OSX build in one DMG again
- Minor bugfixes
-------------------------------------------------------------------------------
0.7.4Beta2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix failure to fetch more par2-files for posts with badly formatted subject lines
- After successful pre-check, preserve a job's position in the queue
- Restore SABnzbd icon for Growl
- Fix "check new releases" option in Config skin
- Separate DMG files for OSX Leopard/SL, Lion and MLion
-------------------------------------------------------------------------------
0.7.4Beta1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- OSX Mountain Lion Notification Center support
- OSX Mountain Lion improved "keep awake" support
- OSX: separate builds: one for Mountain Lion and one for all others
- OSX removed 64bit code
- Scheduler: action can now run on multiple weekdays
- Scheduler: add "remove failed jobs" action
- Special option: rss_odd_titles (see Wiki)
- Support for HTTPS chain files (needed when you buy your own certificate)
- Prevent jobs from showing up in queue and history simultaneously
- Add parameter 'pp_active' to history elements in qstatus API call
- Fix some minor par2 handling bugs
- Prevent potential crash when an actively downloading job is deleted from the queue
- Special option: 'overwrite_files' (See Wiki)
- Don't try an SFV check when a retried job was already successfully verified by par2
- Enable compression of API call results
- Log failed attempts to log in to the Web UI
- A job with "forced" priority should keep that when fetching more par2 files
- Updated translations
-------------------------------------------------------------------------------
0.7.3Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Rename Special "random_server_ip" to "randomize_server_ip" so that we
can force the default to "Off". "On" kills speed on some servers.
- Ignore pseudo NZB files that start with a period in the name
- SFV failure now listed in History instead of issuing warnings
- Translation updates
- "502" errors about payments/credits will now block a server
-------------------------------------------------------------------------------
0.7.3Beta2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Try to keep OSX Mountain Lion awake as long as downloading/postprocessing runs
- Prevent queue deadlock in case of fatally damaged par2 files
- Add RSS filter-enable checkboxes to Plush, Smpl and Classic skins
- Fix problem with saving modified paramters of an already enabled server
- Extend "check new release" option with test releases
-------------------------------------------------------------------------------
0.7.3Beta1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Correct several errors in Sort function
- Improve organization of Config->Servers
- Support for nzbxxx.com
- Make detection of samples less aggressive
- Some minor corrections
-------------------------------------------------------------------------------
0.7.2Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix for NZB-icon issue when 0.7.0 was previously installed
- Check validity of totals9.sab file
- Fix startup problem when localhost has unexpected order of IP addresses
-------------------------------------------------------------------------------
0.7.2RC2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Improve support for nzbsrus.com
- Don't try to show NZB age when not known yet
- Prevent systems with unresolvable hostnames from always using 0.0.0.0
-------------------------------------------------------------------------------
0.7.2RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix fatal error in nzbsrus.com support
- Initial "quota left" was not set correctly when enabling quota
- Report incorrect RSS filter expressions (instead of aborting analysis)
- Improve detection of invalid articles (so that backup server will be tried)
- Windows installer: improve NZB association so that a reboot isn't needed
- Windows installer: don't remove settimngs by default when uninstalling
- Fix sorting of rar files in job so that .rar preceeds .r00
-------------------------------------------------------------------------------
0.7.1Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Disable VC90 check in Windows Installer as long as we're still on Python 2.5
- Windows: make sure \\server\share notation is never seen as a relative path
-------------------------------------------------------------------------------
0.7.1RC5 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix signing of OSX DMG
- Fix endless par2-fetch loop after retrying failed job
- Don't send "bad fetch" email when emailing is off
- Add some support for nzbrus.com's non-VIP limiting
-------------------------------------------------------------------------------
0.7.1RC4 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix failure to grab NZBs from indexers that send compressed files.
-------------------------------------------------------------------------------
0.7.1RC3 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fixed stalling par2 fetches (after first verification run)
- Fixed retry behaviour of NZB fetching from URL
and add handling of nzbsrus.com error codes
- Make sure that all malformed articles are retried on another server
- Add no_ipv6 option that suppresses listing on ::1
(to be used if your system cannot handle that)
- Prevent crash in QuickCheck when expected par2 file wasn't downloaded
- Verification/repair would not be executed properly when one more RAR files
missed their first article.
- API calls "addurl" and "addid" (newzbin) can be used interchangeably
(Fixes a problem in Qouch)
-------------------------------------------------------------------------------
0.7.1RC2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Improved backup of sabnzbd.ini file
Will use backup when original is gone or become corrupt
- Windows: Using ::1 as single webhost address would start IE instead of default browser
-------------------------------------------------------------------------------
0.7.1RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Plush skin: fix problems with pull-down menus in Mobile Safari
- On some Linux and OSX systems using localhost would still make SABnzbd
give access to other computers
- Windows: the installer did not set an icon when associating NZB files with SABnzbd
- Fix problem that the Opera browser had with Config->Servers
- Retry a few times when accessing a mounted drive to create the
final destination folder
- Reduce load caused by WinTray and OSX topmenu
-------------------------------------------------------------------------------
0.7.0Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Updated translations
-------------------------------------------------------------------------------
0.7.0RC2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Suppress permission errors on paths containing ".AppleDouble" or ".DS_Store"
(Required for NAS systems that support Apple AFP shares)
- OSX/Windows: Set article cache to 200M when not already set.
- Pre-check: lower default minimum completion rate to 100.2%
-------------------------------------------------------------------------------
0.7.0RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix for rare crash in par2 fetching
- Another /nomedia fix
- Quota reset wasn't done when quota-reset-time was passed while SABnzbd wasn't running.
- Pre-check: required ratio for NZB without par2 files should be 100%
and not the "safe" ratio
-------------------------------------------------------------------------------
0.7.0Beta8 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Disabled the .nomedia marker file feature.
Those who want to try it, use the "nomedia_marker" setting in Config->Special
It remains an experimental feature without guarantees
- Add missing info in email about failed pre-check
- Updated translations
-------------------------------------------------------------------------------
0.7.0Beta7 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix for .nomedia files not being deleted
- Fix NZB re-queueing (due to .nomedia remaining)
- Polish was missing in Windows installer and Dutch was incorrect
- When Sort renames auxillirary files, it should disregard case
- Fix crash in Wizard on some Linux systems
-------------------------------------------------------------------------------
0.7.0Beta6 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Upgrade unzip for Windows to 6.00 (supports ZIPs above 2G)
- Lower threshold for pre-check to 100.5%
- Fix removal of .nomedia file when using Sorting
- Add Polish translation (using reduced character set)
- Extension-based cleanup list now also removes extension-only files like ".sfv".
- Several small issues
-------------------------------------------------------------------------------
0.7.0Beta5 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Solved serious connection problem with some providers
- Windows Tray has the "restart" entries no under a Troubleshoot menu
- Fix newzbin entries in History's "Source" field
- During unpacking the destination folder will contain a ".nomedia" file
which will keep mediaplayers temporarily from indexing
- Pre-check jobs now require 101% completion rate (with a "special" parameter)
- Unified OSX DMG
-------------------------------------------------------------------------------
0.7.0Beta4 by The SABnzbd-Team
-------------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2013 by "The SABnzbd-team" <team@sabnzbd.org>
The SABnzbd-team is:
@@ -26,6 +26,7 @@ The main contributors and moderators of the translations
Spanish: Syquus
Portuguese (Brazil): lrrosa
Russian: Pavel Maryanov
Polish: Tomasz 'Zen' Napierala
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@@ -1,10 +1,10 @@
SABnzbd 0.7.0
SABnzbd 0.7.9
-------------------------------------------------------------------------------
0) LICENSE
-------------------------------------------------------------------------------
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2013 by "The SABnzbd-team" <team@sabnzbd.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -42,14 +42,17 @@ Use the "Help" button in the web-interface to be directed to the Help Wiki.
-------------------------------------------------------------------------------
3) INSTALL pre-built OSX binaries
-------------------------------------------------------------------------------
Download teh DMG file, mount and drag the SABnzbd icon to Programs.
Download the DMG file, mount and drag the SABnzbd icon to Programs.
Just like you do with so many apps.
Make sure you pick the right folder, depending on your OSX version.
-------------------------------------------------------------------------------
4) INSTALL with only sources
-------------------------------------------------------------------------------
You need to have Python installed and some modules.
You need to have Python installed plus some non-standard Python modules
and a few tools.
Unix/Linux/OSX
Python-2.5, 2.6 or 2.7 http://www.python.org
@@ -57,23 +60,22 @@ Unix/Linux/OSX
OSX Leopard/SnowLeopard
Python 2.6 http://www.activestate.com
OSX Lion Apple Python 2.7 (included in OSX)
OSX Lion/MountainLion
Apple Python 2.7 Included in OSX (default)
Windows
Python-2.7.latest http://www.activestate.com
Essential modules
cheetah-2.0.1+ http://www.cheetahtemplate.org/ (or use "pypm install cheetah")
yenc module >= 0.3 http://sabnzbd.sourceforge.net/yenc-0.3.tar.gz
http://sabnzbd.sourceforge.net/yenc-0.3-w32fixed.zip (Win32-only)
par2cmdline >= 0.4 http://parchive.sourceforge.net/
http://chuchusoft.com/par2_tbb/index.html (multi-core)
Optional modules
unrar >= 3.90+ http://www.rarlab.com/rar_add.htm
unzip >= 5.52 http://www.info-zip.org/
gnu gettext http://www.gnu.org/software/gettext/
gntp https://github.com/kfdm/gntp/ (or use "pypm install gntp")
yenc module >= 0.3 http://sabnzbd.sourceforge.net/yenc-0.3.tar.gz
http://sabnzbd.sourceforge.net/yenc-0.3-w32fixed.zip (Win32-only)
Optional modules Windows
pyopenssl >= 0.11 http://pypi.python.org/pypi/pyOpenSSL

View File

@@ -1,4 +1,4 @@
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2013 by "The SABnzbd-team" <team@sabnzbd.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@@ -21,6 +21,7 @@
!include "MUI2.nsh"
!include "registerExtension.nsh"
!include "FileFunc.nsh"
!include "LogicLib.nsh"
!include "WinVer.nsh"
!include "WinSxSQuery.nsh"
@@ -40,6 +41,7 @@
Delete "${idir}\email\email-sv.tmpl"
Delete "${idir}\email\email-da.tmpl"
Delete "${idir}\email\email-nb.tmpl"
Delete "${idir}\email\email-pl.tmpl"
Delete "${idir}\email\email-ro.tmpl"
Delete "${idir}\email\email-sr.tmpl"
Delete "${idir}\email\email-es.tmpl"
@@ -49,6 +51,7 @@
Delete "${idir}\email\rss-de.tmpl"
Delete "${idir}\email\rss-en.tmpl"
Delete "${idir}\email\rss-nl.tmpl"
Delete "${idir}\email\rss-pl.tmpl"
Delete "${idir}\email\rss-fr.tmpl"
Delete "${idir}\email\rss-sv.tmpl"
Delete "${idir}\email\rss-da.tmpl"
@@ -65,6 +68,7 @@
Delete "${idir}\email\badfetch-fr.tmpl"
Delete "${idir}\email\badfetch-nb.tmpl"
Delete "${idir}\email\badfetch-nl.tmpl"
Delete "${idir}\email\badfetch-pl.tmpl"
Delete "${idir}\email\badfetch-ro.tmpl"
Delete "${idir}\email\badfetch-sr.tmpl"
Delete "${idir}\email\badfetch-sv.tmpl"
@@ -81,6 +85,7 @@
RMDir /r "${idir}\interfaces\wizard"
RMDir /r "${idir}\interfaces\Config"
RMDir "${idir}\interfaces"
RMDir /r "${idir}\win\curl"
RMDir /r "${idir}\win\par2"
RMDir /r "${idir}\win\unrar"
RMDir /r "${idir}\win\unzip"
@@ -114,6 +119,7 @@
Delete "${idir}\IMPORTANT_MESSAGE.txt"
Delete "${idir}\SABnzbd-console.exe"
Delete "${idir}\SABnzbd.exe"
Delete "${idir}\SABnzbd.exe.log"
Delete "${idir}\SABnzbd-helper.exe"
Delete "${idir}\SABnzbd-service.exe"
Delete "${idir}\Sample-PostProc.cmd"
@@ -209,6 +215,7 @@
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "German"
!insertmacro MUI_LANGUAGE "Dutch"
!insertmacro MUI_LANGUAGE "Polish"
!insertmacro MUI_LANGUAGE "Swedish"
!insertmacro MUI_LANGUAGE "Danish"
!insertmacro MUI_LANGUAGE "NORWEGIAN"
@@ -239,6 +246,7 @@ Function .onInit
;--------------------------------
;make sure that the requires MS Runtimes are installed
;
goto nodownload ; Not needed while still using Python25
runtime_loop:
push 'msvcr90.dll'
push 'Microsoft.VC90.CRT,version="9.0.21022.8",type="win32",processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b"'
@@ -291,7 +299,7 @@ SetOutPath "$INSTDIR"
;------------------------------------------------------------------
; Make sure old versions are gone
IfFileExists $INSTDIR\sabnzbd.exe 0 endWarnExist
IfFileExists $INSTDIR\python25.dll 0 endWarnExist
IfFileExists $INSTDIR\python27.dll 0 endWarnExist
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "$(MsgRemoveOld)$\n$\n$(MsgRemoveOld2)" IDOK uninst
Abort
uninst:
@@ -312,7 +320,7 @@ WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninst
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "URLUpdateInfo" 'http://sabnzbd.org/'
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Comments" 'The automated Usenet download tool'
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '$INSTDIR\interfaces\Classic\templates\static\images\favicon.ico'
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 18400
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 25674
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoRepair" -1
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoModify" -1
; write out uninstaller
@@ -343,8 +351,8 @@ Section $(MsgIcon) desktop
SectionEnd ; end of desktop icon section
Section /o $(MsgAssoc) assoc
${registerExtension} "$INSTDIR\nzb.ico" "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File"
;${registerExtension} "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File"
${registerExtension} "$INSTDIR\icons\nzb.ico" "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File"
${RefreshShellIcons}
SectionEnd ; end of file association section
; begin uninstall settings/section
@@ -400,11 +408,11 @@ Section "un.$(MsgDelProgram)" Uninstall
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd"
${unregisterExtension} ".nzb" "NZB File"
${RefreshShellIcons}
SectionEnd ; end of uninstall section
Section "un.$(MsgDelSettings)" DelSettings
Section /o "un.$(MsgDelSettings)" DelSettings
DetailPrint "Uninstall settings $LOCALAPPDATA"
Delete "$LOCALAPPDATA\sabnzbd\sabnzbd.ini"
RMDir /r "$LOCALAPPDATA\sabnzbd"

View File

@@ -1,8 +1,8 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 0.7.0Beta4
Summary: SABnzbd-0.7.0Beta4
Home-page: http://sourceforge.net/projects/sabnzbdplus
Version: 0.7.9
Summary: SABnzbd-0.7.9
Home-page: http://sabnzbd.org
Author: The SABnzbd Team
Author-email: team@sabnzbd.org
License: GNU General Public License 2 (GPL2 or later)

78
README.mkd Normal file
View File

@@ -0,0 +1,78 @@
Release Notes - SABnzbd 0.7.9
===============================
## Bug fix 0.7.9
- Fix fatal error when encountering a malformed article
## Features (0.7.8)
- Use "category" and "password" meta-data in NZB files
(Provided by some indexers)
- Option to abort download when it is clear that not enough data is available
(For removed posts it will be faster than pre-download check)
- Add "Abort" option for encryption detection
- Removed articles are now listed separately in download report
- Special option "wait_for_dfolder", enables waiting for external temp download folder at startup
## Bug fixes (0.7.8)
- Fix problem with %fn substitution in Sorting
- Pre-download check did not work with all servers
- Fix missing Retry link for "Out of retention" jobs.
- API function "addfile" now accepts "nzbname" parameter for ZIP/RAR files with one NZB.
- Prevent retries when an NZB with just samples is retrieved from an indexer
(and you had the "do not download samples" option enabled).
## What's new in 0.7.0
- Download quota management
- Windows: simple system tray menu
- Multi-platform Growl support
- NotifyOSD support for Linux distros that have it
- Option to set maximum number of retries for servers (prevents deadlock)
- Pre-download check to estimate completeness (reliability is limited)
- Prevent partial downloading of par2 files that are not needed yet
- Config->Special for settings previously only available in the sabnzbd.ini file
- For Usenet servers with multiple IP addresses, pick a random one per connection
- Add pseudo-priority "Stop" that will send the job immediately to the post-processing queue
- Allow jobs still waiting for post-processing to be deleted too
- More persistent retries for unreliable indexers
- Single Configuration skin for all others skins (there is an option for the old style)
- Config->Special for settings that were previously only changeable in the sabnzbd.ini file
- Add Spanish, Portuguese (Brazil) and Polish translations
- Individual RSS filter toggle
- Unified OSX DMG
## 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-2013 by "The SABnzbd-team" \<team@sabnzbd.org\>
### IMPORTANT INFORMATION about release 0.7.x
<http://wiki.sabnzbd.org/introducing-0-7-0>
### Known problems and solutions
- Read the file "ISSUES.txt"
### Upgrading from 0.6.x
- Stop SABnzbd
- Install new version
- Start SABnzbd
### Upgrading from 0.5.x
- Stop SABnzbd
- Install new version
- Start SABnzbd.
The organization of the download queue is different from 0.5.x.
0.7.x will finish downloading an existing queue, but you
cannot go back to an older version without losing your queue.
Also, your sabnzbd.ini file will be upgraded, making it
incompatible with release 0.5.x
### Upgrading from 0.4.x
Download your current queue before upgrading.

View File

@@ -1,103 +0,0 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\vieww16360\viewh15680\viewkind0
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
\f0\b\fs48 \cf0 SABnzbd 0.7.0Beta4\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
\b0\fs26 \cf0 \
\b What's new
\b0 \
- Download quota management\
- Windows: simple system tray menu\
- Multi-platform Growl support\
- NotifyOSD support for Linux distros that have it\
- Option to set maximum number of retries for servers (prevents deadlock)\
- Pre-download check to estimate completeness (reliability is limited)\
- Prevent partial downloading of par2 files that are not needed yet\
- Config->Special for settings previously only available in the sabnzbd.ini file\
- For Usenet servers with multiple IP addresses, pick a random one per connection\
- Add pseudo-priority "Stop" that will send the job immediately to the post-processing queue\
- Allow jobs still waiting for post-processing to be deleted too\
- More persistent retries for unreliable indexers\
- Single Configuration skin for all others skins (there is an option for the old style)\
- Config->Special for settings that were previously only changeable in the sabnzbd.ini file\
- Add Spanish and Portuguese (Brazil) translations\
- Individual RSS filter toggle\
\
For problems fixed in Beta4, see CHANGELOG.txt\
\
\b About
\b0 \
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.\
\
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>\
\
There is an extensive Wiki on the use of SABnzbd.\
{\field{\*\fldinst{HYPERLINK "http://wiki.sabnzbd.org/"}}{\fldrslt http://wiki.sabnzbd.org/}}\
\
\b IMPORTANT INFORMATION
\b0 about release 0.6.0:\
{\field{\*\fldinst{HYPERLINK "http://wiki.sabnzbd.org/introducing-0-6-0"}}{\fldrslt http://wiki.sabnzbd.org/introducing-0-6-0}}\
\
\b Known problems and solutions\
\b0 Read the file"ISSUES.txt"
\b \
\b0 \
\
\b\fs40 Upgrading from 0.6.x
\b0\fs26 \
Stop SABnzbd.\
Install new version\
Start SABnzbd.\
\
\b\fs40 Upgrading from 0.5.x
\b0\fs26 \
Stop SABnzbd.\
Uninstall current version, keeping the data.\
Install new version\
Start SABnzbd.\
\
The organization of the download queue is different from 0.5.x.\
0.6.x will finish downloading an existing queue, but you\
cannot go back to an older version without losing your queue.\
Also, your sabnzbd.ini file will be upgraded, making it\
incompatible with release 0.5.x\
\
\b\fs40 \
Upgrading from 0.4.x
\b0\fs26 \
\
\b PLEASE DOWNLOAD YOUR CURRENT QUEUE BEFORE UPGRADING
\b0 \
\
When upgrading from a 0.4.x release such as 0.4.12 your old settings will be kept.\
You will however be given a fresh queue and history. If you have items in your queue\
from the older version of SABnzbd, you can either re-import the nzb files if you kept\
an nzb backup folder, or temporarily go back to 0.4.x until your queue is complete.\
The history is now stored in a better format meaning future upgrades should be backwards\
compatible.\
\
\
\b\fs40 Changes since 0.5.6
\b0\fs26 \
See: {\field{\*\fldinst{HYPERLINK "http://wiki.sabnzbd.org/introducing-0-6-0"}}{\fldrslt http://wiki.sabnzbd.org/introducing-0-6-0}}\
}

View File

@@ -1,32 +0,0 @@
************************ SABnzbd 0.7.0Beta4 ************************
What's new:
- Download quota management
- Windows: simple system tray menu
- Multi-platform Growl support
- NotifyOSD support for Linux distros that have it
- Option to set maximum number of retries for servers (prevents deadlock)
- Pre-download check to estimate completeness (reliability is limited)
- Prevent partial downloading of par2 files that are not needed yet
- Config->Special for settings previously only available in the sabnzbd.ini file
- For Usenet servers with multiple IP addresses, pick a random one per connection
- Add pseudo-priority "Stop" that will send the job immediately to the post-processing queue
- Allow jobs still waiting for post-processing to be deleted too
- More persistent retries for unreliable indexers
- Single Configuration skin for all others skins (there is an option for the old style)
- Config->Special for settings that were previously only changeable in the sabnzbd.ini file
- Add Spanish and Portuguese (Brazil) translations
- Individual RSS filter toggle
For problems fixed in Beta4, see CHANGELOG.txt
About:
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.
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python -OO
# Copyright 2008-2012 The SABnzbd-Team <team@sabnzbd.org>
# Copyright 2008-2013 The SABnzbd-Team <team@sabnzbd.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -16,8 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys
if sys.version_info < (2,5):
print "Sorry, requires Python 2.5 or higher."
if sys.version_info < (2, 5):
print "Sorry, requires Python 2.5, 2.6 or 2.7."
sys.exit(1)
import logging
@@ -28,6 +28,7 @@ import signal
import socket
import platform
import time
import re
try:
import Cheetah
@@ -253,12 +254,13 @@ def print_help():
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"
print " --no_ipv6 Do not listen on IPv6 address [::1]"
def print_version():
print """
%s-%s
Copyright (C) 2008-2012, The SABnzbd-Team <team@sabnzbd.org>
Copyright (C) 2008-2013, The SABnzbd-Team <team@sabnzbd.org>
SABnzbd comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions. It is licensed under the
@@ -524,32 +526,26 @@ def all_localhosts():
return ips
def ipv_localhost(v):
""" Return True if localhost resolves to some IPV4 ('4') or IPV6 ('6') address
def check_resolve(host):
""" Return True if 'host' resolves
"""
try:
info = socket.getaddrinfo('localhost', None)
info = socket.getaddrinfo(host, None)
except:
# localhost does not resolve
# Does not resolve
return False
for item in info:
item = item[4][0]
if v == '4' and ':' not in item:
return True
elif v == '6' and ':' in item:
return True
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 ipv_localhost('4'):
if cherryhost == '0.0.0.0' and not check_resolve('127.0.0.1'):
cherryhost = ''
elif cherryhost == '::' and not ipv_localhost('6'):
elif cherryhost == '::' and not check_resolve('::1'):
cherryhost = ''
if cherryhost is None:
cherryhost = sabnzbd.cfg.cherryhost()
else:
@@ -562,9 +558,18 @@ def get_webhost(cherryhost, cherryport, https_port):
try:
info = socket.getaddrinfo(socket.gethostname(), None)
except:
# Hostname does not resolve, use 0.0.0.0
cherryhost = '0.0.0.0'
info = socket.getaddrinfo(localhost, None)
# 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.'):
@@ -667,28 +672,27 @@ def get_webhost(cherryhost, cherryport, https_port):
return cherryhost, cherryport, browserhost, https_port
def attach_server(host, port, cert=None, key=None):
def attach_server(host, port, cert=None, key=None, chain=None):
""" Define and attach server, optionally HTTPS
"""
http_server = _cpwsgi_server.CPWSGIServer()
http_server.bind_addr = (host, port)
if cert and key:
http_server.ssl_certificate = cert
http_server.ssl_private_key = key
adapter = _cpserver.ServerAdapter(cherrypy.engine, http_server, http_server.bind_addr)
adapter.subscribe()
if not (sabnzbd.cfg.no_ipv6() and '::1' in host):
http_server = _cpwsgi_server.CPWSGIServer()
http_server.bind_addr = (host, port)
if cert and key:
http_server.ssl_certificate = cert
http_server.ssl_private_key = key
http_server.ssl_certificate_chain = chain
adapter = _cpserver.ServerAdapter(cherrypy.engine, http_server, http_server.bind_addr)
adapter.subscribe()
def is_sabnzbd_running(url):
def is_sabnzbd_running(url, timeout=None):
""" Return True when there's already a SABnzbd instance running.
"""
try:
url = '%s&mode=version' % (url)
ver = sabnzbd.newsunpack.get_from_url(url)
if ver and ver.strip(' \n\r\t') == sabnzbd.__version__:
return True
else:
return False
ver = sabnzbd.newsunpack.get_from_url(url, timeout=timeout)
return bool(ver and re.search(r'\d+\.\d+\.', ver))
except:
return False
@@ -708,7 +712,7 @@ def find_free_port(host, currentport):
def check_for_sabnzbd(url, upload_nzbs, allow_browser=True):
""" Check for a running instance of sabnzbd(same version) on this port
""" 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:
@@ -773,7 +777,7 @@ def evaluate_inipath(path):
inipath = os.path.join(path, DEF_INI_FILE)
if os.path.isdir(path):
return inipath
elif os.path.isfile(path):
elif os.path.isfile(path) or os.path.isfile(path + '.bak'):
return path
else:
dirpart, name = os.path.split(path)
@@ -836,7 +840,7 @@ def commandline_handler(frozen=True):
try:
opts, args = getopt.getopt(info, "phdvncw:l:s:f:t:b:2:",
['pause', 'help', 'daemon', 'nobrowser', 'clean', 'logging=',
'weblogging=', 'server=', 'templates',
'weblogging=', 'server=', 'templates', 'no_ipv6',
'template2', 'browser=', 'config-file=', 'force',
'version', 'https=', 'autorestarted', 'repair', 'repair-all',
'log-all', 'no-login', 'pid=', 'new', 'sessions', 'console',
@@ -914,6 +918,7 @@ def main():
new_instance = False
force_sessions = False
osx_console = False
no_ipv6 = False
service, sab_opts, serv_opts, upload_nzbs = commandline_handler()
@@ -1000,6 +1005,8 @@ def main():
elif opt in ('--console',):
re_argv.append(opt)
osx_console = True
elif opt in ('--no_ipv6',):
no_ipv6 = True
sabnzbd.MY_FULLNAME = os.path.normpath(os.path.abspath(sabnzbd.MY_FULLNAME))
sabnzbd.MY_NAME = os.path.basename(sabnzbd.MY_FULLNAME)
@@ -1053,7 +1060,7 @@ def main():
GetProfileInfo(vista_plus)
# Find out where INI file is
inifile = os.path.abspath(sabnzbd.DIR_PROG + '/' + DEF_INI_FILE)
if not os.path.exists(inifile):
if not os.path.exists(inifile) and not os.path.exists(inifile + '.bak'):
inifile = os.path.abspath(sabnzbd.DIR_LCLDATA + '/' + DEF_INI_FILE)
if sabnzbd.DARWIN:
copy_old_files(sabnzbd.DIR_LCLDATA)
@@ -1065,7 +1072,7 @@ def main():
# 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(sabnzbd.DIR_LCLDATA):
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:
@@ -1082,6 +1089,9 @@ def main():
# Set root folders for HTTPS server file paths
sabnzbd.cfg.set_root_folders2()
if no_ipv6:
sabnzbd.cfg.no_ipv6.set(True)
# Determine web host address
cherryhost, cherryport, browserhost, https_port = get_webhost(cherryhost, cherryport, https_port)
enable_https = sabnzbd.cfg.enable_https()
@@ -1200,8 +1210,6 @@ def main():
sabnzbd.cfg.log_backups())
format = '%(asctime)s::%(levelname)s::[%(module)s:%(lineno)d] %(message)s'
if sabnzbd.WIN32:
format += '\r'
rollover_log.setFormatter(logging.Formatter(format))
rollover_log.addFilter(FilterCP3())
sabnzbd.LOGHANDLER = rollover_log
@@ -1341,6 +1349,10 @@ def main():
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)):
@@ -1359,8 +1371,8 @@ def main():
hosts[1] = '::1'
# The Windows binary requires numeric localhost as primary address
if multilocal and cherryhost == 'localhost' and hosts[1] == '127.0.0.1':
cherryhost = '::1'
if multilocal and cherryhost == 'localhost':
cherryhost = hosts[0]
if enable_https:
if https_port:
@@ -1370,14 +1382,15 @@ def main():
# 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)
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)
cherrypy.config.update({'server.ssl_certificate' : https_cert,
'server.ssl_private_key' : https_key })
'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)
@@ -1395,6 +1408,17 @@ def main():
else:
sessions = None
mime_gzip = ('text/html',
'text/plain',
'text/css',
'text/xml',
'text/javascript',
'application/javascript',
'text/x-javascript',
'application/x-javascript',
'text/x-json',
'application/json'
)
cherrypy.config.update({'server.environment': 'production',
'server.socket_host': cherryhost,
'server.socket_port': cherryport,
@@ -1404,7 +1428,7 @@ def main():
'engine.reexec_retry' : 100,
'tools.encode.on' : True,
'tools.gzip.on' : True,
'tools.gzip.mime_types' : ['text/html', 'text/plain', 'text/javascript', 'text/css', 'application/x-javascript'],
'tools.gzip.mime_types' : mime_gzip,
'tools.sessions.on' : bool(sessions),
'tools.sessions.storage_type' : 'file',
'tools.sessions.storage_path' : sessions,
@@ -1495,8 +1519,8 @@ def main():
if sabnzbd.FOUNDATION:
import sabnzbd.osxmenu
sabnzbd.osxmenu.notify("SAB_Launched", None)
growler.send_notification('SABnzbd %s' % (sabnzbd.__version__),
"http://%s:%s/sabnzbd" % (browserhost, cherryport), 'startup')
growler.send_notification('SABnzbd%s' % growler.hostname(),
T('SABnzbd %s started') % sabnzbd.__version__, 'startup')
# Now's the time to check for a new version
check_latest_version()
autorestarted = False
@@ -1539,7 +1563,7 @@ def main():
add_local(f)
# Have to keep this running, otherwise logging will terminate
timer = 0
timer = timer5 = 0
while not sabnzbd.SABSTOP:
if sabnzbd.WIN_SERVICE:
rc = win32event.WaitForMultipleObjects((sabnzbd.WIN_SERVICE.hWaitStop,
@@ -1565,7 +1589,7 @@ def main():
### 30 sec polling tasks
if timer > 9:
timer = 0
# Keep Windows awake (if needed)
# Keep OS awake (if needed)
sabnzbd.keep_awake()
# Restart scheduler (if needed)
scheduler.restart()
@@ -1579,6 +1603,15 @@ def main():
if sabnzbd.WIN_SERVICE and mail:
mail.send('active')
if timer5 > 9:
### 5 minute polling tasks
timer5 = 0
if sabnzbd.cfg.web_watchdog() and not is_sabnzbd_running('%s/api?tickleme=1' % sabnzbd.BROWSER_URL, 120):
autorestarted = True
cherrypy.engine.execv = True
else:
timer5 += 1
else:
timer += 1

View File

@@ -658,7 +658,10 @@ class Request(object):
# Handle cookies differently because on Konqueror, multiple
# cookies come on different lines with the same key
if name == 'Cookie':
self.cookie.load(value)
try:
self.cookie.load(value)
except:
pass
if not dict.__contains__(headers, 'Host'):
# All Internet-based HTTP/1.1 servers MUST respond with a 400

View File

@@ -1,3 +1,4 @@
import logging
import cherrypy
from cherrypy.lib import httpauth
@@ -9,10 +10,10 @@ def check_auth(users, encrypt=None, realm=None):
ah = httpauth.parseAuthorization(cherrypy.request.headers['authorization'])
if ah is None:
raise cherrypy.HTTPError(400, 'Bad Request')
if not encrypt:
encrypt = httpauth.DIGEST_AUTH_ENCODERS[httpauth.MD5]
if callable(users):
try:
# backward compatibility
@@ -20,7 +21,7 @@ def check_auth(users, encrypt=None, realm=None):
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:
@@ -29,23 +30,26 @@ def check_auth(users, encrypt=None, realm=None):
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=cherrypy.request.method,
encrypt=encrypt, realm=realm):
cherrypy.request.login = ah["username"]
return True
if ah.get('username') or ah.get('password'):
logging.info('Attempt to login with wrong credentials from %s',
cherrypy.request.headers['Remote-Addr'])
cherrypy.request.login = False
return False
def basic_auth(realm, users, encrypt=None):
"""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.
@@ -53,23 +57,23 @@ def basic_auth(realm, users, encrypt=None):
"""
if check_auth(users, encrypt):
return
# inform the user-agent this path is protected
cherrypy.response.headers['www-authenticate'] = httpauth.basicAuth(realm)
raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
def digest_auth(realm, users):
"""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):
return
# inform the user-agent this path is protected
cherrypy.response.headers['www-authenticate'] = httpauth.digestAuth(realm)
raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
raise cherrypy.HTTPError(401, "You are not authorized to access that resource")

View File

@@ -1,332 +1,402 @@
import re
import hashlib
import time
import platform
import StringIO
__version__ = '0.8'
#GNTP/<version> <messagetype> <encryptionAlgorithmID>[:<ivValue>][ <keyHashAlgorithmID>:<keyHash>.<salt>]
GNTP_INFO_LINE = re.compile(
'GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)' +
' (?P<encryptionAlgorithmID>[A-Z0-9]+(:(?P<ivValue>[A-F0-9]+))?) ?' +
'((?P<keyHashAlgorithmID>[A-Z0-9]+):(?P<keyHash>[A-F0-9]+).(?P<salt>[A-F0-9]+))?\r\n',
re.IGNORECASE
)
GNTP_INFO_LINE_SHORT = re.compile(
'GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)',
re.IGNORECASE
)
GNTP_HEADER = re.compile('([\w-]+):(.+)')
GNTP_EOL = '\r\n'
__version__ = '0.4'
class BaseError(Exception):
pass
def gntp_error(self):
error = GNTPError(self.errorcode, self.errordesc)
return error.encode()
class ParseError(BaseError):
def gntp_error(self):
error = GNTPError(errorcode=500,errordesc='Error parsing the message')
return error.encode()
errorcode = 500
errordesc = 'Error parsing the message'
class AuthError(BaseError):
def gntp_error(self):
error = GNTPError(errorcode=400,errordesc='Error with authorization')
return error.encode()
errorcode = 400
errordesc = 'Error with authorization'
class UnsupportedError(BaseError):
def gntp_error(self):
error = GNTPError(errorcode=500,errordesc='Currently unsupported by gntp.py')
return error.encode()
errorcode = 500
errordesc = 'Currently unsupported by gntp.py'
class _GNTPBuffer(StringIO.StringIO):
"""GNTP Buffer class"""
def writefmt(self, message="", *args):
"""Shortcut function for writing GNTP Headers"""
self.write((message % args).encode('utf8', 'replace'))
self.write(GNTP_EOL)
class _GNTPBase(object):
info = {
'version':'1.0',
'messagetype':None,
'encryptionAlgorithmID':None
}
_requiredHeaders = []
headers = {}
resources = {}
def add_origin_info(self):
self.add_header('Origin-Machine-Name',platform.node())
self.add_header('Origin-Software-Name','gntp.py')
self.add_header('Origin-Software-Version',__version__)
self.add_header('Origin-Platform-Name',platform.system())
self.add_header('Origin-Platform-Version',platform.platform())
"""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.headers = {}
self.resources = {}
def __str__(self):
return self.encode()
def _parse_info(self,data):
'''
Parse the first line of a GNTP message to get security and other info values
@param data: GNTP Message
@return: GNTP Message information in a dictionary
'''
#GNTP/<version> <messagetype> <encryptionAlgorithmID>[:<ivValue>][ <keyHashAlgorithmID>:<keyHash>.<salt>]
match = re.match('GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)'+
' (?P<encryptionAlgorithmID>[A-Z0-9]+(:(?P<ivValue>[A-F0-9]+))?) ?'+
'((?P<keyHashAlgorithmID>[A-Z0-9]+):(?P<keyHash>[A-F0-9]+).(?P<salt>[A-F0-9]+))?\r\n', data,re.IGNORECASE)
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 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 password: Null to clear password
@param encryptAlgo: Supports MD5,SHA1,SHA256,SHA512
@todo: Support other hash functions
'''
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
"""
hash = {
'MD5': hashlib.md5,
'SHA1': hashlib.sha1,
'SHA256': hashlib.sha256,
'SHA512': hashlib.sha512,
}
self.password = password
self.encryptAlgo = encryptAlgo.upper()
if not password:
self.info['encryptionAlgorithmID'] = None
self.info['keyHashAlgorithm'] = None;
self.info['keyHashAlgorithm'] = None
return
if not self.encryptAlgo in hash.keys():
raise UnsupportedError('INVALID HASH "%s"'%self.encryptAlgo)
raise UnsupportedError('INVALID HASH "%s"' % self.encryptAlgo)
hashfunction = hash.get(self.encryptAlgo)
password = password.encode('utf8')
seed = time.ctime()
salt = hashfunction(seed).hexdigest()
saltHash = hashfunction(seed).digest()
keyBasis = password+saltHash
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 value: Value to decode
@return: Hex string
'''
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)
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):
def _decode_binary(self, rawIdentifier, identifier):
rawIdentifier += '\r\n\r\n'
dataLength = int(identifier['Length'])
pointerStart = self.raw.find(rawIdentifier)+len(rawIdentifier)
pointerStart = self.raw.find(rawIdentifier) + len(rawIdentifier)
pointerEnd = pointerStart + dataLength
data = self.raw[pointerStart:pointerEnd]
if not len(data) == dataLength:
raise ParseError('INVALID_DATA_LENGTH Expected: %s Recieved %s'%(dataLength,len(data)))
raise ParseError('INVALID_DATA_LENGTH Expected: %s Recieved %s' % (dataLength, len(data)))
return data
def _validate_password(self,password):
'''
Validate GNTP Message against stored password
'''
def _validate_password(self, password):
"""Validate GNTP Message against stored password"""
self.password = password
if password == None: raise Exception()
keyHash = self.info.get('keyHash',None)
if password == None:
raise 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 AuthError('Invalid keyHash')
if self.password is None:
raise AuthError('Missing password')
password = self.password.encode('utf8')
saltHash = self._decode_hex(self.info['salt'])
keyBasis = password+saltHash
keyBasis = password + saltHash
key = hashlib.md5(keyBasis).digest()
keyHash = hashlib.md5(key).hexdigest()
if not keyHash.upper() == self.info['keyHash'].upper():
raise AuthError('Invalid Hash')
return True
def validate(self):
'''
Verify required headers
'''
"""Verify required headers"""
for header in self._requiredHeaders:
if not self.headers.get(header,False):
raise ParseError('Missing Notification Header: '+header)
if not self.headers.get(header, False):
raise ParseError('Missing Notification Header: ' + header)
def _format_info(self):
'''
Generate info line for GNTP Message
@return: Info line string
'''
info = u'GNTP/%s %s'%(
"""Generate info line for GNTP Message
:return string:
"""
info = u'GNTP/%s %s' % (
self.info.get('version'),
self.info.get('messagetype'),
)
if self.info.get('encryptionAlgorithmID',None):
info += ' %s:%s'%(
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'%(
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 data:
@return: Dictionary of headers
'''
)
return info
def _parse_dict(self, data):
"""Helper function to parse blocks of GNTP headers into a dictionary
:param string data:
:return dict:
"""
dict = {}
for line in data.split('\r\n'):
match = re.match('([\w-]+):(.+)', line)
if not match: continue
key = match.group(1).strip()
val = match.group(2).strip()
match = GNTP_HEADER.match(line)
if not match:
continue
key = unicode(match.group(1).strip(), 'utf8', 'replace')
val = unicode(match.group(2).strip(), 'utf8', 'replace')
dict[key] = val
return dict
def add_header(self,key,value):
def add_header(self, key, value):
if isinstance(value, unicode):
self.headers[key] = value
else:
self.headers[key] = unicode('%s'%value,'utf8','replace')
def decode(self,data,password=None):
'''
Decode GNTP Message
@param data:
'''
self.headers[key] = unicode('%s' % value, 'utf8', 'replace')
def add_resource(self, data):
"""Add binary resource
:param string data: Binary 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 = data
parts = self.raw.split('\r\n\r\n')
self.info = self._parse_info(data)
self.headers = self._parse_dict(parts[0])
def encode(self):
'''
Encode a GNTP Message
@return: GNTP Message ready to be sent
'''
self.validate()
EOL = u'\r\n'
message = self._format_info() + EOL
"""Encode a generic GNTP Message
:return string: GNTP Message ready to be sent
"""
buffer = _GNTPBuffer()
buffer.writefmt(self._format_info())
#Headers
for k,v in self.headers.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
message += EOL
return message
for k, v in self.headers.iteritems():
buffer.writefmt('%s: %s', k, v)
buffer.writefmt()
#Resources
for resource, data in self.resources.iteritems():
buffer.writefmt('Identifier: %s', resource)
buffer.writefmt('Length: %d', len(data))
buffer.writefmt()
buffer.write(data)
buffer.writefmt()
buffer.writefmt()
return buffer.getvalue()
class GNTPRegister(_GNTPBase):
"""Represents a GNTP Registration Command"""
notifications = []
"""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):
'''
@param data: (Optional) See decode()
@param password: (Optional) Password to use while encoding/decoding messages
'''
self.info['messagetype'] = 'REGISTER'
def __init__(self, data=None, password=None):
_GNTPBase.__init__(self, 'REGISTER')
self.notifications = []
if data:
self.decode(data,password)
self.decode(data, password)
else:
self.set_password(password)
self.add_header('Application-Name', 'pygntp')
self.add_header('Notifications-Count', 0)
self.add_origin_info()
def validate(self):
'''
Validate required headers and validate notification headers
'''
'''Validate required headers and validate notification headers'''
for header in self._requiredHeaders:
if not self.headers.get(header,False):
raise ParseError('Missing Registration Header: '+header)
if not self.headers.get(header, False):
raise ParseError('Missing Registration Header: ' + header)
for notice in self.notifications:
for header in self._requiredNotificationHeaders:
if not notice.get(header,False):
raise ParseError('Missing Notification Header: '+header)
def decode(self,data,password):
'''
Decode existing GNTP Registration message
@param data: Message to decode.
'''
if not notice.get(header, False):
raise ParseError('Missing Notification Header: ' + header)
def decode(self, data, password):
"""Decode existing GNTP Registration message
:param string data: Message to decode
"""
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self._parse_info(data)
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
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):
if notice.get('Notification-Name', False):
self.notifications.append(notice)
elif notice.get('Identifier',False):
notice['Data'] = self._decode_binary(part,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 name: Notification Name
@param enabled: Default Notification to Enabled
'''
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'] = u'%s'%name
notice['Notification-Enabled'] = u'%s'%enabled
notice['Notification-Name'] = u'%s' % name
notice['Notification-Enabled'] = u'%s' % enabled
self.notifications.append(notice)
self.add_header('Notifications-Count', len(self.notifications))
def encode(self):
'''
Encode a GNTP Registration Message
@return: GNTP Registration Message ready to be sent
'''
self.validate()
EOL = u'\r\n'
message = self._format_info() + EOL
"""Encode a GNTP Registration Message
:return string: Encoded GNTP Registration message
"""
buffer = _GNTPBuffer()
buffer.writefmt(self._format_info())
#Headers
for k,v in self.headers.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
for k, v in self.headers.iteritems():
buffer.writefmt('%s: %s', k, v)
buffer.writefmt()
#Notifications
if len(self.notifications)>0:
if len(self.notifications) > 0:
for notice in self.notifications:
message += EOL
for k,v in notice.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
message += EOL
return message
for k, v in notice.iteritems():
buffer.writefmt('%s: %s', k, v)
buffer.writefmt()
#Resources
for resource, data in self.resources.iteritems():
buffer.writefmt('Identifier: %s', resource)
buffer.writefmt('Length: %d', len(data))
buffer.writefmt()
buffer.write(data)
buffer.writefmt()
buffer.writefmt()
return buffer.getvalue()
class GNTPNotice(_GNTPBase):
"""Represents a GNTP Notification Command"""
"""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):
'''
@param data: (Optional) See decode()
@param app: (Optional) Set Application-Name
@param name: (Optional) Set Notification-Name
@param title: (Optional) Set Notification Title
@param password: (Optional) Password to use while encoding/decoding messages
'''
self.info['messagetype'] = 'NOTIFY'
def __init__(self, data=None, app=None, name=None, title=None, password=None):
_GNTPBase.__init__(self, 'NOTIFY')
if data:
self.decode(data,password)
self.decode(data, password)
else:
self.set_password(password)
if app:
@@ -335,105 +405,103 @@ class GNTPNotice(_GNTPBase):
self.add_header('Notification-Name', name)
if title:
self.add_header('Notification-Title', title)
self.add_origin_info()
def decode(self,data,password):
'''
Decode existing GNTP Notification message
@param data: Message to decode.
'''
def decode(self, data, password):
"""Decode existing GNTP Notification message
:param string data: Message to decode.
"""
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self._parse_info(data)
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
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)
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
def encode(self):
'''
Encode a GNTP Notification Message
@return: GNTP Notification Message ready to be sent
'''
self.validate()
EOL = u'\r\n'
message = self._format_info() + EOL
#Headers
for k,v in self.headers.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
message += EOL
return message
self.resources[notice.get('Identifier')] = notice
class GNTPSubscribe(_GNTPBase):
"""Represents a GNTP Subscribe Command"""
def __init__(self,data=None,password=None):
self.info['messagetype'] = 'SUBSCRIBE'
self._requiredHeaders = [
'Subscriber-ID',
'Subscriber-Name',
]
"""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)
self.decode(data, password)
else:
self.set_password(password)
self.add_origin_info()
class GNTPOK(_GNTPBase):
"""Represents a GNTP OK Response"""
"""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):
'''
@param data: (Optional) See _GNTPResponse.decode()
@param action: (Optional) Set type of action the OK Response is for
'''
self.info['messagetype'] = '-OK'
def __init__(self, data=None, action=None):
_GNTPBase.__init__(self, '-OK')
if data:
self.decode(data)
if action:
self.add_header('Response-Action', action)
self.add_origin_info()
class GNTPError(_GNTPBase):
_requiredHeaders = ['Error-Code','Error-Description']
def __init__(self,data=None,errorcode=None,errordesc=None):
'''
@param data: (Optional) See _GNTPResponse.decode()
@param errorcode: (Optional) Error code
@param errordesc: (Optional) Error Description
'''
self.info['messagetype'] = '-ERROR'
"""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)
self.add_origin_info()
def error(self):
return self.headers['Error-Code'],self.headers['Error-Description']
def parse_gntp(data,password=None):
'''
Attempt to parse a message as a GNTP message
@param data: Message to be parsed
@param password: Optional password to be used to verify the message
'''
match = re.match('GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)',data,re.IGNORECASE)
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
"""
match = GNTP_INFO_LINE_SHORT.match(data)
if not match:
raise ParseError('INVALID_GNTP_INFO')
info = match.groupdict()
if info['messagetype'] == 'REGISTER':
return GNTPRegister(data,password=password)
return GNTPRegister(data, password=password)
elif info['messagetype'] == 'NOTIFY':
return GNTPNotice(data,password=password)
return GNTPNotice(data, password=password)
elif info['messagetype'] == 'SUBSCRIBE':
return GNTPSubscribe(data,password=password)
return GNTPSubscribe(data, password=password)
elif info['messagetype'] == '-OK':
return GNTPOK(data)
elif info['messagetype'] == '-ERROR':

View File

@@ -12,10 +12,55 @@ using GNTP
import gntp
import socket
import logging
import platform
__all__ = [
'mini',
'GrowlNotifier',
]
logger = logging.getLogger(__name__)
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):
"""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
"""
growl = GrowlNotifier(
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,
)
class GrowlNotifier(object):
"""Helper class to simplfy sending Growl messages
@@ -27,55 +72,35 @@ class GrowlNotifier(object):
:param string hostname: Remote host
:param integer port: Remote port
"""
applicationName = 'Python GNTP'
notifications = []
defaultNotifications = []
applicationIcon = None
passwordHash = 'MD5'
socketTimeout = 3
#GNTP Specific
password = None
hostname = 'localhost'
port = 23053
def __init__(self, applicationName='Python GNTP', notifications=[],
defaultNotifications=None, applicationIcon=None, hostname='localhost',
password=None, port=23053):
def __init__(self, applicationName=None, notifications=None, defaultNotifications=None, applicationIcon=None, hostname=None, password=None, port=None):
if applicationName:
self.applicationName = applicationName
assert self.applicationName, 'An application name is required.'
if notifications:
self.notifications = list(notifications)
assert self.notifications, 'A sequence of one or more notification names is required.'
if defaultNotifications is not None:
self.applicationName = applicationName
self.notifications = list(notifications)
if defaultNotifications:
self.defaultNotifications = list(defaultNotifications)
elif not self.defaultNotifications:
self.defaultNotifications = list(self.notifications)
else:
self.defaultNotifications = self.notifications
self.applicationIcon = applicationIcon
if applicationIcon is not None:
self.applicationIcon = self._checkIcon(applicationIcon)
elif self.applicationIcon is not None:
self.applicationIcon = self._checkIcon(self.applicationIcon)
#GNTP Specific
if password:
self.password = password
if hostname:
self.hostname = hostname
assert self.hostname, 'Requires valid hostname'
if port:
self.port = int(port)
assert isinstance(self.port, int), 'Requires valid port'
self.password = password
self.hostname = hostname
self.port = int(port)
def _checkIcon(self, data):
'''
Check the icon to see if it's valid
@param data:
@todo Consider checking for a valid URL
If it's a simple URL icon, then we return True. If it's a data icon
then we return False
'''
return data
logger.debug('Checking icon')
return data.startswith('http')
def register(self):
"""Send GNTP Registration
@@ -84,23 +109,26 @@ class GrowlNotifier(object):
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)
logger.debug('Sending registration to %s:%s', self.hostname, self.port)
register = gntp.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:
register.add_header('Application-Icon', self.applicationIcon)
if self._checkIcon(self.applicationIcon):
register.add_header('Application-Icon', self.applicationIcon)
else:
id = register.add_resource(self.applicationIcon)
register.add_header('Application-Icon', id)
if self.password:
register.set_password(self.password, self.passwordHash)
response = self._send('register', register.encode())
if isinstance(response, gntp.GNTPOK):
return True
logger.error('Invalid response %s', response.error())
return response.error()
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):
def notify(self, noteType, title, description, icon=None, sticky=False,
priority=None, callback=None, identifier=None):
"""Send a GNTP notifications
.. warning::
@@ -112,8 +140,13 @@ class GrowlNotifier(object):
: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
.. 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)
logger.debug('Sending notification [%s] to %s:%s', noteType, self.hostname, self.port)
assert noteType in self.notifications
notice = gntp.GNTPNotice()
notice.add_header('Application-Name', self.applicationName)
@@ -126,14 +159,23 @@ class GrowlNotifier(object):
if priority:
notice.add_header('Notification-Priority', priority)
if icon:
notice.add_header('Notification-Icon', self._checkIcon(icon))
if self._checkIcon(icon):
notice.add_header('Notification-Icon', icon)
else:
id = notice.add_resource(icon)
notice.add_header('Notification-Icon', id)
if description:
notice.add_header('Notification-Text', description)
response = self._send('notify', notice.encode())
if isinstance(response, gntp.GNTPOK):
return True
logger.error('Invalid response %s', response.error())
return response.error()
if callback:
notice.add_header('Notification-Callback-Target', callback)
if identifier:
notice.add_header('Notification-Coalescing-ID', identifier)
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"""
@@ -143,30 +185,63 @@ class GrowlNotifier(object):
sub.add_header('Subscriber-Port', port)
if self.password:
sub.set_password(self.password, self.passwordHash)
response = self._send('subscribe', sub.encode())
if isinstance(response, gntp.GNTPOK):
return True
logger.error('Invalid response %s', response.error())
return response.error()
def _send(self, type, data):
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', gntp.__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"""
#logger.debug('To : %s:%s <%s>\n%s', self.hostname, self.port, type, data)
#Less verbose please
logger.debug('To : %s:%s <%s>', self.hostname, self.port, type)
packet.validate()
data = packet.encode()
#logger.debug('To : %s:%s <%s>\n%s', self.hostname, self.port, packet.__class__, data)
#Less verbose
logger.debug('To : %s:%s <%s>', self.hostname, self.port, packet.__class__)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(self.socketTimeout)
s.connect((self.hostname, self.port))
s.send(data.encode('utf8', 'replace'))
try:
s.settimeout(10)
except:
pass
response = gntp.parse_gntp(s.recv(1024))
s.send(data)
recv_data = s.recv(1024)
while not recv_data.endswith("\r\n\r\n"):
recv_data += s.recv(1024)
response = gntp.parse_gntp(recv_data)
s.close()
#logger.debug('From : %s:%s <%s>\n%s', self.hostname, self.port, response.__class__, response)
#Less verbose please
#Less verbose
logger.debug('From : %s:%s <%s>', self.hostname, self.port, response.__class__)
return response
if type(response) == gntp.GNTPOK:
return True
if response.error()[0] == '404' and 'disabled' in response.error()[1]:
# Ignore message saying that user has disabled this class
return True
logger.error('Invalid response: %s', response.error())
return response.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.DEBUG)
mini('Testing mini notification')

View File

@@ -6,59 +6,6 @@
<!--#set global $submenu="newzbin"#-->
<!--#include $webdir + "/inc_cmenu.tmpl"#-->
<h2>Newzbin</h2>
$T('explain-newzbin')<br/><br/>
<form action="saveNewzbin" method="post" autocomplete="off">
<div class="EntryBlock">
<fieldset class="EntryFieldSet">
<legend>$T('accountInfo')</legend>
<strong>$T('opt-username_newzbin'):</strong><br>
$T('explain-username_newzbin')<br>
<input type="text" name="username_newzbin" value="$username_newzbin">
<br>
<br>
<strong>$T('opt-password_newzbin'):</strong><br>
$T('explain-password_newzbin')<br>
<input type="password" name="password_newzbin" value="$password_newzbin">
</fieldset>
</div>
<div class="EntryBlock">
<fieldset class="EntryFieldSet">
<legend>$T('newzbinBookmarks')</legend>
<label><input type="checkbox" name="newzbin_bookmarks" value="1" <!--#if $newzbin_bookmarks > 0 then "checked=1" else ""#--> <strong>$T('opt-newzbin_bookmarks'):</strong></label><br>
$T('explain-newzbin_bookmarks')<br>
<a href="getBookmarks?session=$session">$T('link-getBookmarks')</a>
<br>
<!--#if $bookmarks_list#-->
<a href="hideBookmarks?session=$session">$T('link-HideBM')</a>
<!--#else#-->
<a href="showBookmarks?session=$session">$T('link-ShowBM')</a>
<!--#end if#-->
<br/>
<br/>
<label><input type="checkbox" name="newzbin_unbookmark" value="1" <!--#if $newzbin_unbookmark > 0 then "checked=1" else ""#--> /> <strong>$T('opt-newzbin_unbookmark'):</strong></label><br>
$T('explain-newzbin_unbookmark')<br>
<br/>
<strong>$T('opt-bookmark_rate'):</strong><br>
$T('explain-bookmark_rate')<br>
<input type="text" name="bookmark_rate" value="$bookmark_rate">
</fieldset>
</div>
<!--#if $bookmarks_list#-->
<fieldset class="EntryFieldSet">
<legend>$T('processedBM')</legend>
<!--#for $msgid in $bookmarks_list#-->
<a href="https://$newzbin_url/browse/post/$msgid/" target="_blank">$msgid</a>&nbsp;
<!--#end for#-->
</fieldset>
<!--#end if#-->
<input type="hidden" name="session" value="$session">
<p><input type="submit" value="$T('button-saveChanges')"></p>
</form>
<hr/>
<h2>NzbMatrix</h2>
$T('explain-nzbmatrix')<br/><br/>

View File

@@ -73,6 +73,7 @@
<table>
<tr>
<th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
<th>&nbsp;</th>
<th>$T('rss-order')</th>
<th>$T('rss-type')</th>
<th>$T('rss-filter')</th>
@@ -86,6 +87,7 @@
<form action="upd_rss_filter" method="get">
<tr class="odd">
<td></td>
<td><input type="checkbox" name="enabled" value="1" checked="checked" /></td>
<td></td>
<td>
<select name="filter_type">
@@ -152,6 +154,10 @@
</td>
<form action="upd_rss_filter" method="get">
<td>
<input type="checkbox" name="enabled" value="1" <!--#if $filter[6] == '1' then 'checked="checked"' else ""#--> />
</td>
<td>
<input type="text" size="3" name="new_index" value=$fnum>
</td>
@@ -208,6 +214,7 @@
<input type="hidden" name="feed" value="$feed"/>
<input type="hidden" name="session" value="$session">
<input type="submit" value="$T('button-save')"/>
<!--#if not $rss[$feed].filter_states[$fnum]#-->&nbsp;&nbsp;$T('Incorrect filter')<!--#end if#-->
</td>
</form>
</tr>

View File

@@ -31,16 +31,14 @@ $T('hour'):<br>
<!--#end for#-->
</select>
<br>$T('sch-frequency'): <br>
<select name="dayofweek">
<option value="*" selected>$T('daily')
<option value="1">$T('monday')
<option value="2">$T('tuesday')
<option value="3">$T('wednesday')
<option value="4">$T('thursday')
<option value="5">$T('friday')
<option value="6">$T('saturday')
<option value="7">$T('sunday')
</select>
<input type="checkbox" name="daysofweek" value="1">$T('monday')<br/>
<input type="checkbox" name="daysofweek" value="2">$T('tuesday')<br/>
<input type="checkbox" name="daysofweek" value="3">$T('wednesday')<br/>
<input type="checkbox" name="daysofweek" value="4">$T('thursday')<br/>
<input type="checkbox" name="daysofweek" value="5">$T('friday')<br/>
<input type="checkbox" name="daysofweek" value="6">$T('saturday')<br/>
<input type="checkbox" name="daysofweek" value="7">$T('sunday')<br/>
<br>$T('sch-action'):<br>
<select name="action">
<!--#for $action in $actions#-->

View File

@@ -47,11 +47,13 @@
<a href="$cpath/notify/">$T('cmenu-notif')</a> |
<!--#end if#-->
<!--#if 0#-->
<!--#if $submenu=="indexers"#-->
<a class="current" href="./">$T('cmenu-newzbin')</a> |
<!--#else#-->
<a href="$cpath/indexers/">$T('cmenu-newzbin')</a> |
<!--#end if#-->
<!--#end if#-->
<!--#if $submenu=="categories"#-->
<a class="current" href="./">$T('cmenu-cat')</a> |

View File

@@ -1,6 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>$mbleft MB $T('queued') - SABnzbd $version</title>
<link rel="stylesheet" type="text/css" href="$statpath/static/stylesheets/default.css"/>
<link rel="stylesheet" type="text/css" href="$statpath/static/stylesheets/defaultcolors.css"/>

View File

@@ -17,8 +17,7 @@
<div class="EntryBlock">
<form action="addID" method="get">
<fieldset class="EntryFieldSet">
<legend>$T('add')
<!--#if $varExists('newzbinDetails')#--> $T('reportId') / <!--#end if#-->URL</legend>
<legend>$T('add') URL</legend>
<input type="text" name="id">
<!--#if $cat_list#-->
<select name="cat" >

View File

@@ -0,0 +1,54 @@
uniConfig for SABnzbd 0.7.x
zoggy@sabnzbd.org
========================================================
LIBRARIES USED
jQuery
* Project repository: https://github.com/jquery/jquery
* Dual licensed under the MIT and GPL licenses:
* http://www.gnu.org/licenses/gpl.html
* http://www.opensource.org/licenses/mit-license.php
jQuery UI
* Project repository: https://github.com/jquery/jquery-ui
* Dual licensed under the MIT and GPL licenses:
* http://www.gnu.org/licenses/gpl.html
* http://www.opensource.org/licenses/mit-license.php
jQuery Form Plugin
* Project repository: https://github.com/malsup/form
* Dual licensed under the MIT and GPL licenses:
* http://www.gnu.org/licenses/gpl.html
* http://www.opensource.org/licenses/mit-license.php
jQuery Tools (tabs)
* Project repository: https://github.com/jquerytools/jquerytools
Formalize
* Project repository: https://github.com/nathansmith/formalize
* Dual licensed under the MIT and GPL licenses:
* http://www.gnu.org/licenses/gpl.html
* http://www.opensource.org/licenses/mit-license.php
normalize.css
* Project repository: https://github.com/necolas/normalize.css
* Licensed under public domain
qTip2
* Project repository: https://github.com/craga89/qtip2
* Dual licensed under the MIT and GPL licenses:
* http://www.gnu.org/licenses/gpl.html
* http://www.opensource.org/licenses/mit-license.php
========================================================
IMAGES USED
/images/loading-*.gif
- source: http://www.AjaxLoad.info
/images/flags/*
- source: http://www.famfamfam.com/lab/icons/flags/

View File

@@ -0,0 +1,14 @@
<!-- Content end -->
</div>
<script>
function is_touch_device() {
return !!('ontouchstart' in window) ? 1 : 0;
}
if (is_touch_device() === 1) {
// touch device found
\$('#content').css('overflow-y', 'inherit');
\$('html').css('overflow-y', 'scroll');
}
</script>
</body>
</html>

View File

@@ -0,0 +1,156 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<title>SABnzbd $version - $T('queued'): $mbleft $T('MB')</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="noindex">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
#if $pane == "Config"#
#set global $root = '../'#
#else#
#set global $root = '../../'#
#end if#
<link rel="shortcut icon" href="${root}staticcfg/ico/favicon.ico">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="${root}staticcfg/ico/apple-touch-icon-144x144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="${root}staticcfg/ico/apple-touch-icon-114x114-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="${root}staticcfg/ico/apple-touch-icon-72x72-precomposed.png">
<link rel="apple-touch-icon-precomposed" href="${root}staticcfg/ico/apple-touch-icon-57x57-precomposed.png">
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/style.css" />
<script src="${root}staticcfg/js/script.js"></script>
<script type="text/javascript">
\$.Browser = {
defaults: {
title: 'Choose Directory',
url: '${root}api?mode=browse&output=json&apikey=$session',
autocompleteURL: '${root}api?mode=browse&output=json&compact=1&apikey=$session'
}
};
var config_pane = "$pane";
var help_uri = "$help_uri";
var apikey = "$session";
var confirmWithoutSavingPrompt = "$T('Plush-confirmWithoutSavingPrompt')";
function config_success() {
\$('.saveButton').each(function () {
\$(this).removeAttr("disabled").attr("value", "$T('button-saveChanges')");
});
}
function config_failure() {
\$('.saveButton').each(function () {
\$(this).removeAttr("disabled").attr("value", "$T('smpl-failed')");
});
}
\$(document).ready(function () {
#if $pane != "Servers"#
\$('.col2 H3').click(function () { \$(this).parent().next().toggle() });
#end if#
\$('.sabnzbd_restart').click(function () {
\$('.sabnzbd_restart').each(function () {
\$(this).attr("disabled", "disabled");
});
var msg = "$T('explain-Restart')";
if (confirm(msg.replace(/\<br(\s*\/|)\>/g, '\n'))) {
\$(this).attr("value", "$T('wizard-restarting')");
location.href = '${root}config/restart?session=$session';
}
\$('.sabnzbd_restart').each(function () {
\$(this).removeAttr("disabled");
});
return false;
});
\$('#fullform').ajaxForm({
beforeSubmit: function () {
\$('.saveButton').each(function () {
\$(this).attr("disabled", "disabled").attr("value", "$T('smpl-saving')");
});
},
success: function () {
setTimeout(config_success, 1000);
},
error: function () {
setTimeout(config_failure, 1000);
},
timeout: 3000
});
\$("#sidebar-trigger").click(function () {
if (\$("#sidebar-trigger").hasClass("trigger-left")) {
\$("#sidebar").animate({marginLeft: "-150px", queue: false}, 250);
\$("#sidebar-pane").animate({marginLeft: "-150px", queue: false}, 250);
\$("#content").animate({left: "6px", queue: false}, 250);
\$("#sidebar-trigger").removeClass("trigger-left").addClass("trigger-right");
} else {
\$("#sidebar").animate({marginLeft: "0px", queue: false}, 250);
\$("#sidebar-pane").animate({marginLeft: "0px", queue: false}, 250);
\$("#content").animate({left: "156px", queue: false}, 250);
\$("#sidebar-trigger").removeClass("trigger-right").addClass("trigger-left");
}
});
});
</script>
</head>
<body class="$pane">
<div id="sidebar">
<a href="${root}"><img src="${root}staticcfg/images/logo.png" width="120" height="45" id="logo" alt="[home]" /></a>
<div id="tab-container">
<a href="${root}config/">
<div #if $pane == "Config" then 'class="active"' else ""#>$T('menu-config')</div>
</a>
<a href="${root}config/general/">
<div #if $pane == "General" then 'class="active"' else ""#>$T('cmenu-general')</div>
</a>
<a href="${root}config/folders/">
<div #if $pane == "Folders" then 'class="active"' else ""#>$T('cmenu-folders')</div>
</a>
<a href="${root}config/switches/">
<div #if $pane == "Switches" then 'class="active"' else ""#>$T('cmenu-switches')</div>
</a>
<a href="${root}config/server/">
<div #if $pane == "Servers" then 'class="active"' else ""#>$T('cmenu-servers')</div>
</a>
<a href="${root}config/scheduling/">
<div #if $pane == "Scheduling" then 'class="active"' else ""#>$T('Plush-cmenu-scheduling')</div>
</a>
<a href="${root}config/notify/">
<div #if $pane == "Email" then 'class="active"' else ""#>$T('cmenu-notif')</div>
</a>
<!--#if 0#-->
<a href="${root}config/indexers/">
<div #if $pane == "Index Sites" then 'class="active"' else ""#>$T('cmenu-newzbin')</div>
</a>
<!--#end if#-->
<a href="${root}config/categories/">
<div #if $pane == "Categories" then 'class="active"' else ""#>$T('cmenu-cat')</div>
</a>
<a href="${root}config/sorting/">
<div #if $pane == "Sorting" then 'class="active"' else ""#>$T('cmenu-sorting')</div>
</a>
<a href="${root}config/special/">
<div #if $pane == "Special" then 'class="active"' else ""#>$T('cmenu-special')</div>
</a>
<a href="${root}config/rss/">
<div #if $pane == "RSS" then 'class="active"' else ""#>$T('cmenu-rss')</div>
</a>
<br/>
<a href="$helpuri$help_uri" target="_blank">
<div>$T('menu-help')</div>
</a>
</div>
</div>
<div id="sidebar-pane"><div id="sidebar-trigger" class="trigger-left"></div></div>
<div id="content">
<!-- Content start -->

View File

@@ -0,0 +1,34 @@
<!--#set global $pane="Config"#-->
<!--#set global $help_uri="configure-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<div class="section padTable">
<table id="infoTable">
<tbody>
<tr class="alt"><td class="infoTableHeader">$T('version'): </td><td class="infoTableCell">$version</td></tr>
<tr><td class="infoTableHeader">$T('uptime'): </td><td class="infoTableCell">$uptime</td></tr>
<tr class="alt"><td class="infoTableHeader">$T('confgFile'): </td><td class="infoTableCell">$configfn</td></tr>
<tr><td class="infoTableHeader">$T('cache').capitalize(): </td><td class="infoTableCell"><!--#set $msg=$T('ft-buffer@2')%($cache_art, $cache_size)#-->$msg</td></tr>
<tr class="alt"><td class="infoTableHeader">$T('parameters'): </td><td class="infoTableCell">$cmdline</td></tr>
<tr><td class="infoTableHeader">$T('pythonVersion'): </td><td class="infoTableCell">$sys.version[:120]</td></tr>
<tr class="infoTableSeperator alt"><td class="infoTableHeader">$T('homePage') </td><td class="infoTableCell"><a href="http://sabnzbd.org/" target="_blank">http://sabnzbd.org/</a></td></tr>
<tr><td class="infoTableHeader">$T('menu-wiki') </td><td class="infoTableCell"><a href="http://wiki.sabnzbd.org/faq" target="_blank">http://wiki.sabnzbd.org/faq</a></td></tr>
<tr class="alt"><td class="infoTableHeader">$T('menu-forums') </td><td class="infoTableCell"><a href="http://forums.sabnzbd.org/" target="_blank">http://forums.sabnzbd.org/</a></td></tr>
<tr><td class="infoTableHeader">$T('source') </td><td class="infoTableCell"><a href="https://github.com/sabnzbd/sabnzbd" target="_blank">https://github.com/sabnzbd/sabnzbd</a></td></tr>
<tr class="alt"><td class="infoTableHeader">$T('menu-irc') </td><td class="infoTableCell"><a href="irc://irc.synirc.net/#sabnzbd"><i>#sabnzbd</i> on <i>irc.synirc.net</i></a> $T('or') (<a href="http://sabnzbd.org/live-chat/" target="_blank">webchat</a>)</td></tr>
</tbody>
</table>
</div>
<div class="padding alt">
<h5 class="copyright">Copyright &copy; 2008-2013 The SABnzbd Team &lt;<span style="color: #0000ff;">team@sabnzbd.org</span>&gt;</h5>
<p class="copyright"><small>$T('yourRights')</small></p>
</div>
<!--#if $news_items#-->
<div class="padding">
<iframe frameborder=0 width=100% src="http://sabnzbdplus.sourceforge.net/version/news.html"></iframe>
</div>
<!--#end if#-->
</div>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,115 @@
<!--#set global $pane="Categories"#-->
<!--#set global $help_uri="configure-categories-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<div class="section">
<div class="padTable">
<p>
$T('explain-catTags') $T('explain-catTags2')<br/>
</p>
<div class="field-pair">
<h5 class="darkred nomargin">$T('explain-relFolder'): <span class="path">$defdir</span></h5>
</div>
<!--#set $odd = False#-->
<!--#set $cur = 0#-->
<!--#for $slot in $slotinfo#-->
<!--#set $odd = not $odd#-->
<!--#set $cur = $cur+1#-->
<form action="save" method="get">
<table class="catTable">
<!--#if $cur == 1#-->
<tr>
<th>$T('category')</th>
<th>$T('priority')</th>
<th>$T('mode')</th>
<!--#if $script_list#--><th>$T('script')</th><!--#end if#-->
<th>$T('catFolderPath')</th>
<th>$T('catTags')</th>
<th>&nbsp;</th>
</tr>
<!--#end if#-->
<tr class="<!--#if $odd then "alt" else ""#-->" <!--#if $slot.name == '*'#-->style="background-color: #FFFFE0;"<!--#end if#-->>
<td>
<input type="hidden" name="session" value="$session" />
<input type="hidden" value="$slot.name" name="name" />
<!--#if $slot.name != '*'#-->
<input type="text" name="newname" value="$slot.name" size="10" />
<!--#else#-->
<input type="text" name="newname" value="$T('default')" disabled="disabled" size="10" />
<!--#end if#-->
</td>
<td>
<select name="priority">
<!--#if $slot.name != '*'#-->
<option value="-100" <!--#if $slot.priority == -100 then 'selected="selected" class="selected"' else ""#-->>$T('default')</option>
<!--#end if#-->
<option value="2" <!--#if $slot.priority == 2 then 'selected="selected" class="selected"' else ""#-->>$T('pr-force')</option>
<option value="1" <!--#if $slot.priority == 1 then 'selected="selected" class="selected"' else ""#-->>$T('pr-high')</option>
<option value="0" <!--#if $slot.priority == 0 then 'selected="selected" class="selected"' else ""#-->>$T('pr-normal')</option>
<option value="-1" <!--#if $slot.priority == -1 then 'selected="selected" class="selected"' else ""#-->>$T('pr-low')</option>
<option value="-2" <!--#if $slot.priority == -2 then 'selected="selected" class="selected"' else ""#-->>$T('pr-paused')</option>
</select>
</td>
<td>
<select name="pp">
<!--#if $slot.name != '*'#-->
<option value="" <!--#if $slot.pp == "" then 'selected="selected" class="selected"' else ""#-->>$T('default')</option>
<!--#end if#-->
<option value="0" <!--#if $slot.pp == "0" then 'selected="selected" class="selected"' else ""#-->>$T('pp-none')</option>
<option value="1" <!--#if $slot.pp == "1" then 'selected="selected" class="selected"' else ""#-->>$T('pp-repair')</option>
<option value="2" <!--#if $slot.pp == "2" then 'selected="selected" class="selected"' else ""#-->>$T('pp-unpack')</option>
<option value="3" <!--#if $slot.pp == "3" then 'selected="selected" class="selected"' else ""#-->>$T('pp-delete')</option>
</select>
</td>
<!--#if $script_list#-->
<td>
<select name="script">
<!--#for $sc in $script_list#-->
<!--#if not ($sc == 'Default' and $slot.name == '*')#-->
<option value="$sc" <!--#if $slot.script.lower() == $sc.lower() then 'selected="selected" class="selected"' else ""#-->>$Tspec($sc)</option>
<!--#end if#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td><input type="text" name="dir" value="$slot.dir" size="30" /></td>
<td><input type="text" name="newzbin" value="$slot.newzbin" size="30" /></td>
<td class="nowrap">
<input type="submit" class="Save" value="<!--#if $cur == 2 then $T('button-add') else $T('button-save')#-->" />
<!--#if $slot.name and $slot.name != '*'#-->
<input type="button" class="delCat" value="$T('button-x')" />
<!--#end if#-->
</td>
</tr>
</table>
</form>
<!--#end for#-->
</div>
</div>
</div>
<script>
\$(document).ready(function(){
\$('.delCat').click(function(){
var theForm = \$(this).closest("form");
theForm.attr("action", "delete").submit();
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,118 @@
<!--#set global $pane="Folders"#-->
<!--#set global $help_uri="configure-folders-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveDirectories" method="post" name="fullform" id="fullform">
<input type="hidden" id="session" name="session" value="$session" />
<div class="section">
<div class="col2">
<h3>$T('userFolders')</h3>
<p>$T('explain-folderConfig')</p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_home</span></h5>
</div>
<div class="field-pair alt">
<label class="config" for="download_dir">$T('opt-download_dir')</label>
<input type="text" name="download_dir" id="download_dir" value="$download_dir" size="45" />
<span class="desc">$T('explain-download_dir')</span>
</div>
<div class="field-pair">
<label class="config" for="download_free">$T('opt-download_free')</label>
<input type="text" name="download_free" id="download_free" value="$download_free" size="8" />
<span class="desc">$T('explain-download_free')</span>
</div>
<div class="field-pair alt">
<label class="config" for="complete_dir">$T('opt-complete_dir')</label>
<input type="text" name="complete_dir" id="complete_dir" value="$complete_dir" size="45" />
<span class="desc">$T('explain-complete_dir')</span>
</div>
<div class="field-pair <!--#if $nt then "disabled" else "" #-->">
<label class="config" for="permissions">$T('opt-permissions')</label>
<input type="text" name="permissions" id="permissions" value="$permissions" size="8" <!--#if $nt then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-permissions')</span>
</div>
<div class="field-pair alt">
<label class="config" for="dirscan_dir">$T('opt-dirscan_dir')</label>
<input type="text" name="dirscan_dir" id="dirscan_dir" value="$dirscan_dir" size="45" />
<span class="desc">$T('explain-dirscan_dir')</span>
</div>
<div class="field-pair">
<label class="config" for="dirscan_speed">$T('opt-dirscan_speed')</label>
<input type="number" name="dirscan_speed" id="dirscan_speed" value="$dirscan_speed" size="8" min="0" max="3600" />
<span class="desc">$T('explain-dirscan_speed')</span>
</div>
<div class="field-pair alt">
<label class="config" for="script_dir">$T('opt-script_dir')</label>
<input type="text" name="script_dir" id="script_dir" value="$script_dir" size="45" />
<span class="desc">$T('explain-script_dir')</span>
</div>
<div class="field-pair">
<label class="config" for="email_dir">$T('opt-email_dir')</label>
<input type="text" name="email_dir" id="email_dir" value="$email_dir" size="45" />
<span class="desc">$T('explain-email_dir')</span>
</div>
<div class="field-pair alt">
<label class="config" for="password_file">$T('opt-password_file')</label>
<input type="text" name="password_file" id="password_file" value="$password_file" size="45" />
<span class="desc">$T('explain-password_file')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('systemFolders')</h3>
<p>$T('explain-folderConfig')</p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_lcldata</span></h5>
</div>
<div class="field-pair alt">
<label class="config" for="admin_dir">$T('opt-admin_dir')</label>
<input type="text" name="admin_dir" id="admin_dir" value="$admin_dir" size="45" />
<span class="desc">$T('explain-admin_dir1')</span>
<span class="desc">$T('explain-admin_dir2')</span>
</div>
<div class="field-pair">
<label class="config" for="log_dir">$T('opt-log_dir')</label>
<input type="text" name="log_dir" id="log_dir" value="$log_dir" size="45" />
<span class="desc">$T('explain-log_dir')</span>
</div>
<div class="field-pair alt">
<label class="config" for="nzb_backup_dir">$T('opt-nzb_backup_dir')</label>
<input type="text" name="nzb_backup_dir" id="nzb_backup_dir" value="$nzb_backup_dir" size="45" />
<span class="desc">$T('explain-nzb_backup_dir')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<script>
\$(document).ready(function(){
\$('#download_dir').fileBrowser({ title: 'Select $T('opt-download_dir')' });
\$('#complete_dir').fileBrowser({ title: 'Select $T('opt-complete_dir')' });
\$('#dirscan_dir').fileBrowser({ title: 'Select $T('opt-dirscan_dir')' });
\$('#script_dir').fileBrowser({ title: 'Select $T('opt-script_dir')' });
\$('#email_dir').fileBrowser({ title: 'Select $T('opt-email_dir')' });
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,236 @@
<!--#set global $pane="General"#-->
<!--#set global $help_uri="configure-general-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveGeneral" method="post" name="fullform" id="fullform" novalidate>
<input type="hidden" id="session" name="session" value="$session" />
<div class="section">
<div class="col2">
<h3>$T('webServer')</h3>
<p><b>$T('restartRequired')</b></p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="host">$T('opt-host')</label>
<input type="url" name="host" id="host" value="$host" size="40" />
<span class="desc">$T('explain-host')</span>
</div>
<div class="field-pair">
<label class="config" for="port">$T('opt-port')</label>
<input type="text" name="port" id="port" value="$port" size="8" />
<span class="desc">$T('explain-port')</span>
</div>
<div class="field-pair alt">
<label class="config" for="username">$T('opt-web_username')</label>
<input type="text" name="username" id="username" value="$username" size="30" />
<span class="desc">$T('explain-web_username')</span>
</div>
<div class="field-pair">
<label class="config" for="password">$T('opt-web_password')</label>
<input type="password" name="password" id="password" value="$password" size="30" />
<span class="desc">$T('explain-web_password')</span>
</div>
<div class="field-pair alt">
<label class="config" for="web_dir">$T('opt-web_dir')</label>
<select name="web_dir" id="web_dir">
<!--#for $webline in $web_list#-->
<!--#if $webline.lower() == $web_dir.lower()#-->
<option value="$webline" selected="selected" class="selected">$webline</option>
<!--#else#-->
<option value="$webline">$webline</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-web_dir')</span>
</div>
<div class="field-pair">
<label class="config" for="web_dir2">$T('opt-web_dir2')</label>
<select name="web_dir2" id="web_dir2">
<!--#for $webline in $web_list2#-->
<!--#if $webline.lower() == $web_dir2.lower()#-->
<option value="$webline" selected="selected" class="selected">$webline</option>
<!--#else#-->
<option value="$webline">$webline</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-web_dir2')</span>
</div>
<div class="field-pair alt">
<label class="config" for="language">$T('opt-language')</label>
<select name="language" id="language" id="language" class="select">
<!--#for $webline in $lang_list#-->
<!--#if $webline[0].lower() == $language.lower()#-->
<option value="$webline[0]" selected="selected" class="selected">$webline[1]</option>
<!--#else#-->
<option value="$webline[0]">$webline[1]</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-language')</span>
</div>
<div class="field-pair">
<label class="config" for="disable_api_key">$T('opt-disableApikey')</label>
<input type="checkbox" name="disable_api_key" id="disable_api_key" value="1" <!--#if int($disable_api_key) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-disableApikey')</span>
</div>
<div class="field-pair alt">
<label class="config" for="apikey">$T('opt-apikey')</label>
<input type="text" id="apikey" value="$session" size="35" />
<input type="button" value="$T('button-apikey')" id="generate_new_apikey" />
<input type="button" value="$T('qr-code')" title="$T('explain-qr-code')" class="show_qrcode" rel="$session" />
<span class="desc">$T('explain-apikey')</span>
</div>
<div class="field-pair">
<label class="config" for="nzbkey">$T('opt-nzbkey')</label>
<input type="text" id="nzbkey" value="$nzb_key" size="35" />
<input type="button" value="$T('button-apikey')" id="generate_new_nzbkey" />
<input type="button" value="$T('qr-code')" title="$T('explain-qr-code')" class="show_qrcode" rel="$nzb_key" />
<span class="desc">$T('explain-nzbkey')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('httpsSupport')</h3>
<p><b>$T('restartRequired')</b></p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_lcldata</span></h5>
</div>
<div class="field-pair alt <!--#if int($have_ssl) == 0 then "disabled" else ""#-->">
<label class="config" for="enable_https">$T('opt-enable_https')</label>
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked"' else ""#--> <!--#if int($have_ssl) == 0 then "disabled" else ""#--> />
<span class="desc">$T('explain-enable_https')</span>
</div>
<div class="field-pair">
<label class="config" for="https_port">$T('opt-https_port')</label>
<input type="text" name="https_port" id="https_port" value="$https_port" size="8" />
<span class="desc">$T('explain-https_port')</span>
</div>
<div class="field-pair alt">
<label class="config" for="https_cert">$T('opt-https_cert')</label>
<input type="text" name="https_cert" id="https_cert" value="$https_cert" size="50" />
<span class="desc">$T('explain-https_cert')</span>
</div>
<div class="field-pair">
<label class="config" for="https_key">$T('opt-https_key')</label>
<input type="text" name="https_key" id="https_key" value="$https_key" size="50" />
<span class="desc">$T('explain-https_key')</span>
</div>
<div class="field-pair alt">
<label class="config" for="https_chain">$T('opt-https_chain')</label>
<input type="text" name="https_chain" id="https_chain" value="$https_chain" size="50" />
<span class="desc">$T('explain-https_chain')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('tuning')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="bandwidth_limit">$T('opt-bandwidth_limit')</label>
<input type="number" name="bandwidth_limit" id="bandwidth_limit" value="$bandwidth_limit" size="8" step="1024" min="0" />
<span class="desc">$T('explain-bandwidth_limit')</span>
</div>
<div class="field-pair">
<label class="config" for="cache_limit">$T('opt-cache_limitstr')</label>
<input type="text" name="cache_limit" id="cache_limit" value="$cache_limit" size="8" />
<span class="desc">$T('explain-cache_limitstr')</span>
</div>
<div class="field-pair alt">
<label class="config" for="cleanup_list">$T('opt-cleanup_list')</label>
<input type="text" name="cleanup_list" id="cleanup_list" value="$cleanup_list" size="50"/>
<span class="desc">$T('explain-cleanup_list')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<script>
\$(document).ready(function(){
\$('#apikey, #nzbkey').click(function () { \$(this).select() });
\$('#generate_new_apikey').click(function () {
if (confirm("$T('Plush-confirm')")) {
$.ajax({
type: "POST",
url: "../../tapi",
data: {mode:'config', name:'set_apikey', apikey: \$('#apikey').val()},
success: function(msg){
\$('#apikey').val(msg);
window.location.reload();
}
});
}
});
\$('#generate_new_nzbkey').click(function () {
if (confirm("$T('Plush-confirm')")) {
$.ajax({
type: "POST",
url: "../../tapi",
data: {mode:'config', name:'set_nzbkey', apikey: \$('#apikey').val()},
success: function(msg){
\$('#nzbkey').val(msg);
window.location.reload();
}
});
}
});
\$('.show_qrcode').each(function () {
var qrkey = \$(this).attr('rel'),
qrcode = \$('<img />', {
src: 'https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=' + qrkey,
alt: 'loading...',
width: 300,
height: 300
});
\$(this).qtip( {
content: {
text: qrcode
},
position: {
my: 'center',
at: 'center',
target: \$(window)
},
show: {
event: 'click',
solo: true,
modal: true
},
hide: false,
style: 'ui-tooltip-light ui-tooltip-rounded ui-tooltip-shadow ui-tooltip-qrcode'
});
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,79 @@
<!--#set global $pane="Index Sites"#-->
<!--#set global $help_uri="configure-indexers-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveNewzbin" method="post" name="fullform" id="fullform">
<input type="hidden" id="session" name="session" value="$session" />
<div class="section">
<div class="col2">
<h3>NzbMatrix $T('accountInfo')</h3>
<p>$T('explain-nzbmatrix')</p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="matrix_username">$T('opt-username_matrix')</label>
<input type="text" name="matrix_username" id="matrix_username" value="$matrix_username" size="30" />
<span class="desc">$T('explain-username_matrix')</span>
</div>
<div class="field-pair">
<label class="config" for="matrix_apikey">$T('opt-apikey_matrix')</label>
<input type="text" name="matrix_apikey" id="matrix_apikey" value="$matrix_apikey" size="35" />
<span class="desc">$T('explain-apikey_matrix')</span>
</div>
<div class="field-pair alt">
<label class="config" for="matrix_del_bookmark">$T('opt-newzbin_unbookmark')</label>
<input type="checkbox" name="matrix_del_bookmark" id="matrix_del_bookmark" value="1" <!--#if int($matrix_del_bookmark) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-newzbin_unbookmark')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<script>
\$(document).ready(function(){
\$('#matrix_apikey').click(function(){ \$(this).select() });
\$('#getBookmarks2').click(function(){ window.location='getBookmarks?session='+apikey; });
\$('#hideBookmarks').click(function(){ window.location='hideBookmarks?session='+apikey; });
\$('#showBookmarks').click(function(){ window.location='showBookmarks?session='+apikey; });
});
</script>
<script>
\$(document).ready(function(){
\$('#getBookmarks').click(function(event){
\$.ajax({
type: "GET",
url: "../../tapi",
data: {mode: 'newzbin', name: 'get_bookmarks', output: 'json', apikey: '$session' },
beforeSend: function(){
\$('#getBookmarks').attr("disabled", "disabled");
\$('#getBookmarks-result').removeClass("success failure").addClass("loading");
},
complete: function(){
\$('#getBookmarks').removeAttr("disabled");
\$('#getBookmarks-result').removeClass("loading");
},
success: function(data){
if(data.status == true)
\$('#getBookmarks-result').addClass("success");
else {
\$('#getBookmarks-result').addClass("failure")
alert(data.error);
}
}
});
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,189 @@
<!--#set global $pane="Email"#-->
<!--#set global $help_uri="configure-notifications-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveEmail" method="post" name="fullform" id="fullform" novalidate>
<input type="hidden" id="session" name="session" value="$session" />
<div class="section">
<div class="col2">
<h3>$T('emailOptions')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="email_endjob_radio">$T('opt-email_endjob')</label>
<select name="email_endjob" id="email_endjob">
<option value="0" <!--#if int($email_endjob) == 0 then 'selected="selected" class="selected"' else ""#--> >$T('email-never')</option>
<option value="1" <!--#if int($email_endjob) == 1 then 'selected="selected" class="selected"' else ""#--> >$T('email-always')</option>
<option value="2" <!--#if int($email_endjob) == 2 then 'selected="selected" class="selected"' else ""#--> >$T('email-errorOnly')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="email_full">$T('opt-email_full')</label>
<input type="checkbox" name="email_full" id="email_full" value="1" <!--#if int($email_full) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-email_full')</span>
</div>
<div class="field-pair alt">
<label class="config" for="email_rss">$T('opt-email_rss')</label>
<input type="checkbox" name="email_rss" id="email_rss" value="1" <!--#if int($email_rss) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-email_rss')</span>
</div>
<div class="field-pair">
<label class="config" for="email_dir">$T('opt-email_dir')</label>
<input type="text" name="email_dir" id="email_dir" value="$email_dir" size="45" />
<span class="desc">$T('explain-email_dir')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('emailAccount')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="email_server">$T('opt-email_server')</label>
<input type="text" name="email_server" id="email_server" value="$email_server" size="40" />
<span class="desc">$T('explain-email_server')</span>
</div>
<div class="field-pair">
<label class="config" for="email_to">$T('opt-email_to')</label>
<input type="email" name="email_to" id="email_to" value="$email_to" size="40" />
<span class="desc">$T('explain-email_to')</span>
</div>
<div class="field-pair alt">
<label class="config" for="email_from">$T('opt-email_from')</label>
<input type="email" name="email_from" id="email_from" value="$email_from" size="40" />
<span class="desc">$T('explain-email_from')</span>
</div>
<div class="field-pair">
<label class="config" for="email_account">$T('opt-email_account')</label>
<input type="email" name="email_account" id="email_account" value="$email_account" size="30" />
<span class="desc">$T('explain-email_account')</span>
</div>
<div class="field-pair alt">
<label class="config" for="email_pwd">$T('opt-email_pwd')</label>
<input type="password" name="email_pwd" id="email_pwd" value="$email_pwd" size="30" />
<span class="desc">$T('explain-email_pwd')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('link-testEmail')" id="test_email" rel="$T('askTestEmail')" />
<span id="testmail-result" class="icon path darkred">&nbsp;</span>
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('growlSettings')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="notify_classes">$T('opt-notify_classes')</label>
<select name="notify_classes" multiple="multiple" class="multiple_cats">
<!--#for $item in $notify_list#-->
<option value="$item" <!--#if $item in $notify_classes then 'selected="selected"' else ""#--> >$T($notify_texts[$item])</option>
<!--#end for#-->
</select>
<span class="desc">$T('explain-notify_classes')</span>
</div>
<div class="field-pair <!--#if not $have_ncenter then "disabled" else "" #-->">
<label class="config" for="ncenter_enable">$T('opt-ncenter_enable')</label>
<input type="checkbox" name="ncenter_enable" id="ncenter_enable" value="1" <!--#if int($ncenter_enable) > 0 then 'checked="checked"' else ""#--> <!--#if not $have_ncenter then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-ncenter_enable')</span>
</div>
<div class="field-pair alt <!--#if not $have_ntfosd then "disabled" else "" #-->">
<label class="config" for="ntfosd_enable">$T('opt-ntfosd_enable')</label>
<input type="checkbox" name="ntfosd_enable" id="ntfosd_enable" value="1" <!--#if int($ntfosd_enable) > 0 then 'checked="checked"' else ""#--> <!--#if not $have_ntfosd then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-ntfosd_enable')</span>
</div>
<div class="field-pair" >
<label class="config" for="growl_enable">$T('opt-growl_enable')</label>
<input type="checkbox" name="growl_enable" id="growl_enable" value="1" <!--#if int($growl_enable) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-growl_enable')</span>
</div>
<div class="field-pair alt">
<label class="config" for="growl_server">$T('opt-growl_server')</label>
<input type="text" name="growl_server" id="growl_server" value="$growl_server" size="40" />
<span class="desc">$T('explain-growl_server')</span>
</div>
<div class="field-pair">
<label class="config" for="growl_password">$T('opt-growl_password')</label>
<input type="password" name="growl_password" id="growl_password" value="$growl_password" size="30" />
<span class="desc">$T('explain-growl_password')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('testNotify')" id="test_notification" />
<span id="testnotice-result" class="icon path darkred">&nbsp;</span>
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<script>
\$(document).ready(function(){
\$('#email_dir').fileBrowser({ title: 'Select $T('opt-email_dir')' });
\$('#test_email').click(function () {
if (confirm(\$('#test_email').attr('rel'))) {
\$.ajax({
type: "GET",
url: "../../tapi",
data: {mode: 'test_email', apikey: '$session', output: 'json' },
beforeSend: function () {
\$('#test_email').attr("disabled", "disabled");
\$('#testmail-result').removeClass("success failure").addClass("loading").html('$T('post-Verifying')');
},
complete: function () {
\$('#test_email').removeAttr("disabled");
\$('#testmail-result').removeClass("loading");
},
success: function (data) {
if (data.status == true) {
\$('#testmail-result').addClass("success").html('$T('smpl-emailsent')');
} else {
\$('#testmail-result').addClass("failure").html(data.error);
}
}
});
}
});
\$('#test_notification').click(function () {
\$.ajax({
type: "GET",
url: "../../tapi",
data: {mode: 'test_notif', apikey: '$session', output: 'json' },
beforeSend: function () {
\$('#test_notification').attr("disabled", "disabled");
\$('#testnotice-result').removeClass("success failure").addClass("loading").html('$T('post-Verifying')');
},
complete: function () {
\$('#test_notification').removeAttr("disabled");
\$('#testnotice-result').removeClass("loading");
},
success: function (data) {
if (data.status == true) {
\$('#testnotice-result').addClass("success").html('$T('smpl-notesent')');
} else {
\$('#testnotice-result').addClass("failure").html(data.error);
}
}
});
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,575 @@
<!--#set global $pane="RSS"#-->
<!--#set global $help_uri="configure-rss-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<!--#if not $active_feed#-->
<div class="section">
<div class="padTable">
<p>$T('explain-RSS')</p>
<form action="add_rss_feed" method="post" novalidate>
<input type="hidden" name="session" value="$session">
<table class="catTable">
<tr>
<th>&nbsp;</th>
<th>$T('name')</th>
<th>$T('feed') URL</th>
<th>&nbsp;</th>
</tr>
<tr class="even">
<td><input type="checkbox" name="enable" value="1" /></td>
<td><input type="text" name="feed" size="20" value="$feed" placeholder="unique feed name" /></td>
<td><input type="url" name="uri" size="35" /></td>
<td class="nowrap">
<input type="submit" class="Save" value="$T('button-add')" />
</td>
</tr>
</table>
</form>
<br/>
<form action="save_rss_feed" method="post" novalidate>
<input type="hidden" name="session" value="$session" />
<table id="subscriptions">
<tbody>
<!--#set $feeds = sorted($rss.keys(), cmp=lambda x,y: cmp(x.lower(), y.lower()))#--><!--#slurp#-->
<!--#set $odd = False#--><!--#slurp#-->
<!--#for $feed_item in $feeds#--><!--#slurp#-->
<!--#set $odd = not $odd#--><!--#slurp#-->
<tr class="data-row <!--#if $odd then "alt" else ""#-->" >
<td class="chk">
<input type="checkbox" class="toggleFeedCheckbox" name="enable" value="1" <!--#if int($rss[$feed_item]['enable']) != 0 then 'checked="checked"' else ""#--> rel="$feed_item" />
</td>
<td class="title">
<div class="subscription-title">
<a href="?feed=$rss[$feed_item]['link']" class="path feed">
<div class="favicon" style="background-image: url(&quot;http://www.google.com/s2/favicons?domain=$rss[$feed_item]['baselink']&amp;alt=feed&quot;);"></div>
<span class="<!--#if int($rss[$feed_item]['enable']) != 0 then 'feed_enabled"' else "feed_disabled"#-->">$feed_item</span>
</a>
</div>
<!-- <input type="text" name="newfeed" value="$feed_item" size="25" readonly="readonly" class="readonly" /> -->
</td>
<td class="controls">
<input type="button" class="testFeed" value="$T('Read')" rel="$feed_item" />
<input type="hidden" name="uri" value="$rss[$feed_item]['uri']" size="75" />
<input type="button" class="editFeed" value="$T('Edit') URL" rel="$feed_item" />
<input type="button" class="delFeed" value="$T('button-x')" rel="$feed_item" />
</td>
</tr>
<tr class="feed-row <!--#if $odd then "alt" else ""#-->">
<td></td>
<td colspan="2">
<div>$rss[$feed_item]['uri']</div>
</td>
</tr>
<!--#end for#-->
</tbody>
</table>
</form>
<!--#if $feeds#-->
<br/>
<form action="rss_now" method="post" novalidate>
<input type="hidden" name="session" value="$session" />
<input type="submit" class="readAll" value="$T('button-rssNow')" />
</form>
<!--#end if#-->
</div>
</div>
<div class="section">
<form action="save_rss_rate" method="post">
<input type="hidden" name="session" value="$session" />
<div class="col1">
<fieldset>
<div class="field-pair">
<label class="config narrow" for="rss_rate">$T('opt-rss_rate')</label>
<input type="number" name="rss_rate" id="rss_rate" value="$rss_rate" size="8" min="15" max="1440" />
<input type="submit" value="$T('button-save')" />
<span class="desc narrow">$T('explain-rss_rate')</span>
</div>
</fieldset>
</div><!-- /col1 -->
</form>
</div>
<!--#end if#-->
<!--#if $active_feed#-->
<!--#set $feed = $active_feed#-->
<div class="section">
<div class="padTable">
<h2 class="nomargin activeRSS"><a href="${root}config/rss/">$T('cmenu-rss')</a> &raquo; <a href="$rss[$active_feed]['uri']" onclick="window.open(this.href); return false;">$active_feed</a></h2>
<!--#if $error#-->
<h3 class="darkred">$error</h3>
<!--#end if#-->
<form action="upd_rss_feed" method="post">
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="feed" value="$feed" />
<input type="hidden" name="uri" value="$rss[$feed]['uri']" />
<table class="catTable">
<thead>
<tr>
<th>&nbsp;</th>
<th>$T('rss-order')</th>
<th>$T('rss-type')</th>
<th>$T('rss-filter')</th>
<!--#if $rss[$feed]['pick_cat']#-->
<th>$T('category')</th>
<!--#end if#-->
<th>$T('priority')</th>
<th>$T('mode')</th>
<!--#if $rss[$feed]['pick_script']#-->
<th>$T('script')</th>
<!--#end if#-->
<th>&nbsp;</th>
</tr>
</thead>
<!-- default / global filter -->
<tbody>
<tr class="default">
<td>
<input type="checkbox" disabled="disabled" class="hidden" />
</td>
<td>
<input type="text" disabled="disabled" size="1" class="hidden" />
</td>
<td>
<select name="filter_type" disabled="disabled" class="hidden" >
<option value="A" selected="selected"> $T('rss-accept')</option>
<option value="M"> $T('rss-must')</option>
<option value="R"> $T('rss-reject')</option>
<option value="C"> $T('rss-mustcat')</option>
</select>
</td>
<td>
<input type="text" disabled="disabled" value="" size="25" class="hidden" />
</td>
<!--#if $rss[$feed]['pick_cat']#-->
<td>
<select name="cat">
<!--#for $ct in $cat_list#-->
<option value="$ct" <!--#if $ct == $rss[$feed]['cat'] then 'selected="selected"' else ""#-->>$Tspec($ct)</option><!--#slurp#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td>
<select name="priority">
<option value="-100" <!--#if $rss[$feed]['priority'] == -100 then 'selected="selected"' else ''#-->>$T('default')</option>
<option value="2" <!--#if $rss[$feed]['priority'] == 2 then 'selected="selected"' else ''#-->>$T('pr-force')</option>
<option value="1" <!--#if $rss[$feed]['priority'] == 1 then 'selected="selected"' else ''#-->>$T('pr-high')</option>
<option value="0" <!--#if $rss[$feed]['priority'] == 0 then 'selected="selected"' else ''#-->>$T('pr-normal')</option>
<option value="-1" <!--#if $rss[$feed]['priority'] == -1 then 'selected="selected"' else ''#-->>$T('pr-low')</option>
<option value="-2" <!--#if $rss[$feed]['priority'] == -2 then 'selected="selected"' else ''#-->>$T('pr-paused')</option>
</select>
</td>
<td>
<select name="pp">
<option value="" <!--#if $rss[$feed]['pp'] == "" then 'selected="selected"' else ''#-->>$T('default')</option>
<option value="0" <!--#if $rss[$feed]['pp'] == "0" then 'selected="selected"' else ''#-->>$T('pp-none')</option>
<option value="1" <!--#if $rss[$feed]['pp'] == "1" then 'selected="selected"' else ''#-->>$T('pp-repair')</option>
<option value="2" <!--#if $rss[$feed]['pp'] == "2" then 'selected="selected"' else ''#-->>$T('pp-unpack')</option>
<option value="3" <!--#if $rss[$feed]['pp'] == "3" then 'selected="selected"' else ''#-->>$T('pp-delete')</option>
</select>
</td>
<!--#if $rss[$feed]['pick_script']#-->
<td>
<select name="script">
<!--#for $sc in $script_list#-->
<option value="$sc" <!--#if $sc == $rss[$feed]['script'] then 'selected="selected"' else ""#-->>$Tspec($sc)</option><!--#slurp#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td>
<input type="submit" class="Save" value="$T('button-save')" />
</td>
</tr>
</tbody>
</table>
</form>
<!-- add new filter -->
<form action="upd_rss_filter" method="post">
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="index" value="$rss[$feed]['filtercount']" />
<input type="hidden" name="feed" value="$feed" />
<table class="catTable">
<tbody>
<tr>
<td>
<input type="checkbox" name="enabled" value="1" checked="checked" />
</td>
<td>
<input type="text" name="new_index" size="1" />
</td>
<td>
<select name="filter_type">
<option value="A" selected="selected"> $T('rss-accept')</option>
<option value="M"> $T('rss-must')</option>
<option value="R"> $T('rss-reject')</option>
<option value="C"> $T('rss-mustcat')</option>
</select>
</td>
<td>
<input type="text" name="filter_text" value="" size="25" />
</td>
<!--#if $rss[$feed]['pick_cat']#-->
<td>
<select name="cat">
<!--#for $ct in $cat_list#-->
<option value="$ct" <!--#if $ct == 'Default' then 'selected="selected"' else ""#-->>$Tspec($ct)</option><!--#slurp#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td>
<select name="priority">
<option value="-100" selected="selected">$T('default')</option>
<option value="2">$T('pr-force')</option>
<option value="1">$T('pr-high')</option>
<option value="0">$T('pr-normal')</option>
<option value="-1">$T('pr-low')</option>
<option value="-2">$T('pr-paused')</option>
</select>
</td>
<td>
<select name="pp">
<option value="" selected="selected">$T('default')</option>
<option value="0">$T('pp-none')</option>
<option value="1">$T('pp-repair')</option>
<option value="2">$T('pp-unpack')</option>
<option value="3">$T('pp-delete')</option>
</select>
</td>
<!--#if $rss[$feed]['pick_script']#-->
<td>
<select name="script">
<!--#for $sc in $script_list#-->
<option value="$sc" <!--#if $sc == 'Default' then 'selected="selected"' else ""#-->>$Tspec($sc)</option><!--#slurp#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td>
<input type="submit" class="Save" value="$T('button-add')" />
</td>
</tr>
</tbody>
</table>
</form>
<!--#set $odd = False#--><!--#slurp#-->
<!--#set $fnum = 0#--><!--#slurp#-->
<!--#for $filter in $rss[$feed].filters#--><!--#slurp#-->
<!--#set $odd = not $odd#--><!--#slurp#-->
<form action="upd_rss_filter" method="post">
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="index" value="$fnum" />
<input type="hidden" name="feed" value="$feed" />
<table class="catTable">
<tbody>
<tr class="<!--#if $odd then "alt" else ""#-->">
<td>
<input type="checkbox" name="enabled" value="1" <!--#if $filter[6] == '1' then 'checked="checked"' else ""#--> />
</td>
<td>
<input type="text" name="new_index" value="$fnum" size="1" />
</td>
<td>
<select name="filter_type">
<option value="A" <!--#if $filter[3] == "A" then 'selected="selected"' else ""#-->> $T('rss-accept')</option>
<option value="M" <!--#if $filter[3] == "M" then 'selected="selected"' else ""#-->> $T('rss-must')</option>
<option value="R" <!--#if $filter[3] == "R" then 'selected="selected"' else ""#-->> $T('rss-reject')</option>
<option value="C" <!--#if $filter[3] == "C" then 'selected="selected"' else ""#-->> $T('rss-mustcat')</option>
</select>
</td>
<td>
<input type="text" name="filter_text" value="$filter[4]" size="25" />
</td>
<!--#if $rss[$feed]['pick_cat']#-->
<td>
<select name="cat">
<!--#for $ct in $cat_list#-->
<option value="$ct" <!--#if $ct == $filter[0] then 'selected="selected"' else ""#-->>$Tspec($ct)</option><!--#slurp#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td>
<select name="priority">
<option value="-100" <!--#if $filter[5] == "-100" then 'selected="selected"' else ""#-->>$T('default')</option>
<option value="2" <!--#if $filter[5] == "2" then 'selected="selected"' else ""#-->>$T('pr-force')</option>
<option value="1" <!--#if $filter[5] == "1" then 'selected="selected"' else ""#-->>$T('pr-high')</option>
<option value="0" <!--#if $filter[5] == "0" then 'selected="selected"' else ""#-->>$T('pr-normal')</option>
<option value="-1" <!--#if $filter[5] == "-1" then 'selected="selected"' else ""#-->>$T('pr-low')</option>
<option value="-2" <!--#if $filter[5] == "-2" then 'selected="selected"' else ""#-->>$T('pr-paused')</option>
</select>
</td>
<td>
<select name="pp">
<option value="" <!--#if $filter[1] == "" then 'selected="selected"' else ""#-->>$T('default')</option>
<option value="0" <!--#if $filter[1] == "0" then 'selected="selected"' else ""#-->>$T('pp-none')</option>
<option value="1" <!--#if $filter[1] == "1" then 'selected="selected"' else ""#-->>$T('pp-repair')</option>
<option value="2" <!--#if $filter[1] == "2" then 'selected="selected"' else ""#-->>$T('pp-unpack')</option>
<option value="3" <!--#if $filter[1] == "3" then 'selected="selected"' else ""#-->>$T('pp-delete')</option>
</select>
</td>
<!--#if $rss[$feed]['pick_script']#-->
<td>
<select name="script">
<!--#for $sc in $script_list#-->
<option value="$sc" <!--#if $sc == $filter[2] then 'selected="selected"' else ""#-->>$Tspec($sc)</option><!--#slurp#-->
<!--#end for#-->
</select>
</td>
<!--#end if#-->
<td>
<input type="submit" class="Save" value="$T('button-save')" />
<input type="button" class="delFilter" value="$T('button-x')" />
<!--#if not $rss[$feed].filter_states[$fnum]#-->&nbsp;&nbsp;$T('Incorrect filter')<!--#end if#-->
</td>
</tr>
</tbody>
</table>
</form>
<!--#set $fnum = $fnum+1#-->
<!--#end for#-->
<form action="download_rss_feed" method="post">
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="feed" value="$feed" />
<div class="padding">
<input type="button" class="testFeed" value="$T('button-preFeed')" rel="$feed" />
<input type="submit" value="$T('button-forceFeed')" />
<input type="button" class="cleanFeed" value="$T('button-clear') $T('link-download')" />
</div>
</form>
</div>
</div>
<br/>
<div style="padding-left: 10px; border-bottom: 1px solid #DFDEDE;">
<ul class="tabs">
<li><a href="#">$T('rss-matched') <span class="count"><!--#echo len($matched)#--></span></a></li>
<li><a href="#">$T('rss-notMatched') <span class="count"><!--#echo len($unmatched)#--></span></a></li>
<li><a href="#">$T('rss-done') <span class="count"><!--#echo len($downloaded)#--></span></a></li>
</ul>
</div>
<div class="tab-content padTable">
<!--#if $matched#-->
<table class="catTable">
<!--#set $odd = False#--><!--#slurp#-->
<!--#set $cur = 0#--><!--#slurp#-->
<!--#for $job in $matched#--><!--#slurp#-->
<!--#set $odd = not $odd#--><!--#slurp#-->
<!--#set $cur = $cur+1#--><!--#slurp#-->
<!--#if $cur == 1#-->
<thead>
<tr>
<th>$T('link-download')</th>
<th>$T('rss-skip')</th>
<th>$T('rss-filter')</th>
<th>$T('sort-title')</th>
</tr>
</thead>
<!--#end if#-->
<tr class="infoTableSeperator <!--#if $odd then "alt" else ""#-->">
<td>
<form action="download" method="get">
<input type="hidden" value="$feed" name="feed" />
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="url" value="$job[0]" />
<input type="hidden" name="nzbname" value="$job[4]" />
<input type="submit" value="$T('link-download')" />
</form>
</td>
<td class="align-center">$job[2]</td>
<td class="align-center">
<span>$job[3]</span>
</td>
<td>$job[1]</td>
</tr>
<!--#end for#-->
</table>
<!--#else#-->
$T('none')
<!--#end if#-->
</div>
<div class="tab-content padTable">
<!--#if $unmatched#-->
<table class="catTable">
<!--#set $odd = False#--><!--#slurp#-->
<!--#set $cur = 0#--><!--#slurp#-->
<!--#for $job in $unmatched#--><!--#slurp#-->
<!--#set $odd = not $odd#--><!--#slurp#-->
<!--#set $cur = $cur+1#--><!--#slurp#-->
<!--#if $cur == 1#-->
<thead>
<tr>
<th>$T('link-download')</th>
<th>$T('rss-skip')</th>
<th>$T('rss-filter')</th>
<th>$T('sort-title')</th>
</tr>
</thead>
<!--#end if#-->
<tr class="infoTableSeperator <!--#if $odd then "alt" else ""#-->">
<td>
<form action="download" method="get">
<input type="hidden" value="$feed" name="feed" />
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="url" value="$job[0]" />
<input type="hidden" name="nzbname" value="$job[4]" />
<input type="submit" value="$T('link-download')" />
</form>
</td>
<td class="align-center">$job[2]</td>
<td class="align-center">
<span>$job[3]</span>
</td>
<td>$job[1]</td>
</tr>
<!--#end for#-->
</table>
<!--#else#-->
$T('none')
<!--#end if#-->
</div>
<div class="tab-content padTable">
<!--#if $downloaded#-->
<form action="clean_rss_jobs" method="post">
<input type="hidden" value="$feed" name="feed" />
<input type="hidden" name="session" value="$session" />
<table class="catTable">
<!--#set $odd = False#--><!--#slurp#-->
<!--#set $cur = 0#--><!--#slurp#-->
<!--#for $job in $downloaded#--><!--#slurp#-->
<!--#set $odd = not $odd#--><!--#slurp#-->
<!--#set $cur = $cur+1#--><!--#slurp#-->
<!--#if $cur == 1#-->
<thead>
<tr>
<th>$T('sort-title')</th>
</tr>
</thead>
<!--#end if#-->
<tr class="infoTableSeperator <!--#if $odd then "alt" else ""#-->">
<td>$job</td>
</tr>
<!--#end for#-->
</table>
</form>
<!--#else#-->
$T('none')
<!--#end if#-->
</div>
<!--#end if#-->
</div><!-- /colmask -->
<script>
function urlencode(str) {
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
}
\$(document).ready(function(){
\$('.editFeed').click(function(){
var oldURI = \$(this).prev().val();
var newURI = prompt("$T('feed') URL", oldURI );
if(newURI != "" && newURI !== null) {
var whichFeed = \$(this).attr("rel");
\$.ajax({
type: "POST",
url: "save_rss_feed",
data: {feed: whichFeed, uri: newURI, session: "$session" }
}).done(function( msg ) {
location.reload();
});
} else {
return false;
}
});
\$('.delFeed').click(function(e){
e.preventDefault();
if ( confirm("$T('confirm')") ) {
var whichFeed = \$(this).attr("rel");
\$.ajax({
type: "POST",
url: "del_rss_feed",
data: {feed: whichFeed, session: "$session" }
}).done(function( msg ) {
location.reload();
});
}
});
\$('.testFeed').click(function(){
var whichFeed = \$(this).attr("rel");
\$.ajax({
type: "POST",
url: "test_rss_feed",
data: {feed: whichFeed, session: "$session" }
}).done(function( msg ) {
location = '?feed=' + urlencode(whichFeed);
// location.reload();
});
});
\$('.toggleFeedCheckbox').click(function(){
var whichFeed = \$(this).attr("rel");
\$.ajax({
type: "POST",
url: "toggle_rss_feed",
data: {feed: whichFeed, session: "$session" }
}).done(function() {
location.reload();
});
});
\$('.cleanFeed').click(function(){
var theForm = \$(this).closest("form");
theForm.attr("action", "clean_rss_jobs").submit();
});
\$('.delFilter').click(function(){
var theForm = \$(this).closest("form");
theForm.attr("action", "del_rss_filter").submit();
});
\$(function() {
\$("ul.tabs").tabs("div.tab-content");
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,100 @@
<!--#set global $pane="Scheduling"#-->
<!--#set global $help_uri="configure-scheduling-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<%
import time
t = time.localtime()
hour = t[3]
if hour != 23:
hour += 1
else:
hour = 0
%>
<div class="colmask">
<div class="section">
<div class="col2">
<h3>$T('addSchedule')</h3>
</div><!-- /col2 -->
<form action="addSchedule" method="post">
<input type="hidden" id="session" name="session" value="$session" />
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="hour">$T('hour').capitalize() : $T('minute').capitalize()</label>
<select name="hour" id="hour">
<!--#for $i in range(24)#-->
<option value="$i" <!--#if hour == i then 'selected="selected"' else ""#--> > $str($i).zfill(2) </option>
<!--#end for#-->
</select>&nbsp;<b>:</b>&nbsp;<select name="minute" id="minute">
<!--#for $i in range(60)#-->
<option value="$i"> $str($i).zfill(2) </option>
<!--#end for#-->
</select>
</div>
<div class="field-pair">
<label class="config" for="daysofweek">$T('sch-frequency')</label>
<div class="checkbox-days">
<p><input type="checkbox" name="daysofweek" value="1"><label>$T('monday')</label></p>
<p><input type="checkbox" name="daysofweek" value="2"><label>$T('tuesday')</label></p>
<p><input type="checkbox" name="daysofweek" value="3"><label>$T('wednesday')</label></p>
<p><input type="checkbox" name="daysofweek" value="4"><label>$T('thursday')</label></p>
<p><input type="checkbox" name="daysofweek" value="5"><label>$T('friday')</label></p>
<p><input type="checkbox" name="daysofweek" value="6"><label>$T('saturday')</label></p>
<p><input type="checkbox" name="daysofweek" value="7"><label>$T('sunday')</label></p>
</div>
</div>
<div class="field-pair alt">
<label class="config" for="action">$T('sch-action')</label>
<select name="action" id="action">
<!--#for $action in $actions#-->
<option value="$action">$actions_lng[$action]</option>
<!--#end for#-->
</select>
</div>
<div class="field-pair">
<label class="config" for="arguments">$T('sch-arguments')</label>
<input type="text" name="arguments" id="arguments" value="" size="20" />
</div>
<div class="field-pair">
<input type="submit" value="$T('button-addSchedule')" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
</form>
<div class="section">
<div class="col2">
<h3>$T('currentSchedules')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<!--#if $schedlines#-->
<!--#set $schednum = 0#-->
<!--#set $odd = True#-->
<!--#for $line in $schedlines#-->
<!--#set $odd = not $odd#-->
<form action="delSchedule" method="post">
<input type="hidden" name="session" id="session" value="$session">
<input type="hidden" name="line" id="line" value="$line"/>
<div class="field-pair infoTableSeperator<!--#if $odd then "" else " alt"#-->">
<input class="float-left" type="submit" value="$T('button-x')" />
<div class="scheduleEntry">
<span class="time">$taskinfo[$schednum][1]:$taskinfo[$schednum][2]</span><span class="frequency">$taskinfo[$schednum][3]</span> <span class="darkred">$taskinfo[$schednum][4]</span>
</div>
</div>
</form>
<!--#set $schednum = $schednum+1#-->
<!--#end for#-->
<!--#else#-->
<div class="field-pair">
<label class="config">$T('none')</label>
</div>
<!--#end if#-->
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
</div><!-- /colmask -->
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,220 @@
<!--#set global $pane="Servers"#-->
<!--#set global $help_uri="configure-servers-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="addServer" method="post" novalidate>
<input type="hidden" name="session" value="$session" />
<div id="addServer">
<div class="padding alt">
<input type="button" value="$T('button-addServer')" id="addServerButton" />
</div>
</div>
<div class="section" id="addServerContent" style="display: none;">
<div class="col2">
<h3>$T('addServer')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="enable">$T('srv-enable')</label>
<input type="checkbox" name="enable" id="enable" value="1" checked="checked" />
<span class="desc">$T('srv-enable')</span>
</div>
<div class="field-pair">
<label class="config" for="host">$T('srv-host')</label>
<input type="text" name="host" id="host" size="40" />
</div>
<div class="field-pair alt">
<label class="config" for="port">$T('srv-port')</label>
<input type="text" name="port" id="port" size="8" />
</div>
<div class="field-pair">
<label class="config" for="username">$T('srv-username')</label>
<input type="text" name="username" id="username" size="30" />
</div>
<div class="field-pair alt">
<label class="config" for="password">$T('srv-password')</label>
<input type="password" name="password" id="password" size="30" />
</div>
<div class="field-pair">
<label class="config" for="connections">$T('srv-connections')</label>
<input type="number" name="connections" id="connections" size="8" min="0" max="100" />
</div>
<div class="field-pair alt">
<label class="config" for="retention">$T('srv-retention')</label>
<input type="number" name="retention" id="retention" size="8" min="0" /> <i>$T('days')</i>
</div>
<div class="field-pair">
<label class="config" for="timeout">$T('srv-timeout')</label>
<input type="number" name="timeout" id="timeout" size="8" min="30" /> <i>$T('seconds')</i>
</div>
<div class="field-pair alt <!--#if int($have_ssl) == 0 then "disabled" else ""#-->">
<label class="config" for="ssl">$T('srv-ssl')</label>
<input type="checkbox" name="ssl" id="ssl" value="1" <!--#if int($have_ssl) == 0 then "disabled=\"disabled\"" else ""#--> />
<span class="desc">$T('srv-ssl')</span>
</div>
<div class="field-pair">
<label class="config" for="fillserver">$T('srv-fillserver')</label>
<input type="checkbox" name="fillserver" id="fillserver" value="1" />
<span class="desc">$T('srv-fillserver')</span>
</div>
<div class="field-pair alt">
<label class="config" for="optional">$T('srv-optional')</label>
<input type="checkbox" name="optional" id="optional" value="1" />
<span class="desc">$T('srv-optional')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-addServer')" />
<input type="button" value="$T('button-testServer')" class="testServer" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
</form>
<!--#set $slist = $servers.keys()#-->
<!--#$slist.sort()#-->
<!--#set $cur = 0#-->
<!--#for $server in $slist#-->
<!--#set $cur = $cur + 1#-->
<form action="saveServer" method="post" id="fullform" novalidate>
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="server" value="$server" />
<div class="section">
<div class="col2">
<h3>$servers[$server]['name']</h3>
<p>
<table><tr>
<td><input type="checkbox" class="toggleServerCheckbox" name="q_enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then 'checked="checked"' else ""#--> rel="$server" /></td>
<td>&nbsp;$T('enabled')</td>
</tr></table>
</p>
<input type="button" value="$T('button-clrServer')" class="clrServer" />
<input type="button" value="$T('showDetails')" class="showserver" />
</div><!-- /col2 -->
<div class="col1" style="display:none;">
<fieldset>
<div class="field-pair alt">
<label class="config" for="enable$cur">$T('srv-enable')</label>
<input type="checkbox" name="enable" id="enable$cur" value="1" <!--#if int($servers[$server]['enable']) != 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('srv-enable')</span>
</div>
<div class="field-pair">
<label class="config" for="host$cur">$T('srv-host')</label>
<input type="text" name="host" id="host$cur" value="$servers[$server]['host']" size="40" />
</div>
<div class="field-pair alt">
<label class="config" for="port$cur">$T('srv-port')</label>
<input type="text" name="port" id="port$cur" value="$servers[$server]['port']" size="8" />
</div>
<div class="field-pair">
<label class="config" for="username$cur">$T('srv-username')</label>
<input type="text" name="username" id="username$cur" value="$servers[$server]['username']" size="30" />
</div>
<div class="field-pair alt">
<label class="config" for="password$cur">$T('srv-password')</label>
<input type="password" name="password" id="password$cur" value="$servers[$server]['password']" size="30" />
</div>
<div class="field-pair">
<label class="config" for="connections$cur">$T('srv-connections')</label>
<input type="number" name="connections" id="connections$cur" value="$servers[$server]['connections']" size="8" min="0" max="100" />
</div>
<div class="field-pair alt">
<label class="config" for="retention$cur">$T('srv-retention')</label>
<input type="number" name="retention" id="retention$cur" value="$servers[$server]['retention']" size="8" min="0" /> <i>$T('days')</i>
</div>
<div class="field-pair">
<label class="config" for="timeout$cur">$T('srv-timeout')</label>
<input type="number" name="timeout" id="timeout$cur" value="$servers[$server]['timeout']" size="8" min="30" /> <i>$T('seconds')</i>
</div>
<div class="field-pair alt <!--#if int($have_ssl) == 0 then "disabled" else ""#-->">
<label class="config" for="ssl$cur">$T('srv-ssl')</label>
<input type="checkbox" name="ssl" id="ssl$cur" value="1" <!--#if int($servers[$server]['ssl']) != 0 and int($have_ssl) == 1 then 'checked="checked"' else ""#--> <!--#if int($have_ssl) == 0 then "disabled=\"disabled\"" else ""#--> />
<span class="desc">$T('srv-ssl')</span>
</div>
<div class="field-pair">
<label class="config" for="fillserver$cur">$T('srv-fillserver')</label>
<input type="checkbox" name="fillserver" id="fillserver$cur" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('srv-fillserver')</span>
</div>
<div class="field-pair alt">
<label class="config" for="optional$cur">$T('srv-optional')</label>
<input type="checkbox" name="optional" id="optional$cur" value="1" <!--#if int($servers[$server]['optional']) != 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('srv-optional')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-testServer')" class="testServer" />
<input type="button" value="$T('button-delServer')" class="delServer" />
</div>
</fieldset>
</div><!-- /col1 -->
<div class="col2" style="display:block;">
<!--#if 'amounts' in $servers[$server]#-->
<b>$T('srv-bandwidth'):</b><br/>
$T('total'): $(servers[$server]['amounts'][0])B<br/>
$T('today'): $(servers[$server]['amounts'][3])B<br/>
$T('thisWeek'): $(servers[$server]['amounts'][2])B<br/>
$T('thisMonth'): $(servers[$server]['amounts'][1])B
<!--#end if#-->
</div>
</div><!-- /section -->
</form>
<!--#end for#-->
</div><!-- /colmask -->
<script>
\$(document).ready(function(){
\$('.showserver').click(function () {
\$(this).parent().next().toggle();
\$(this).parent().next().next().toggle();
if (\$(this).attr("value") == "$T('showDetails')") {
\$(this).attr("value", "$T('hideDetails')");
} else {
\$(this).attr("value", "$T('showDetails')");
}
});
\$('#addServerButton').click(function(){
\$('#addServer').hide();
\$('#addServerContent').show();
});
\$('.testServer').click(function(event){
\$(this).attr("disabled", "disabled")
\$.ajax({
type: "POST",
url: "../../tapi",
data: "mode=config&amp;name=test_server&amp;" + \$(this).parents('form:first').serialize() + "&amp;apikey=" + \$('#apikey').val(),
success: function(msg){
alert(msg);
\$(event.target).removeAttr("disabled")
}
});
});
\$('.delServer').click(function(){
if( confirm("$T('Plush-confirm')") )
\$(this).parents('form:first').attr('action','delServer').submit();
return false;
});
\$('.clrServer').click(function(){
if( confirm("$T('Plush-confirm')") )
\$(this).parents('form:first').attr('action','clrServer').submit();
return false;
});
\$('.toggleServerCheckbox').click(function(){
var whichServer = \$(this).attr("rel");
\$.ajax({
type: "POST",
url: "toggleServer",
data: {server: whichServer, session: "$session" }
}).done(function() {
location.reload();
});
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,543 @@
<!--#set global $pane="Sorting"#-->
<!--#set global $help_uri="configure-sorting-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSorting" method="post" name="fullform" id="fullform">
<input type="hidden" id="session" name="session" value="$session" />
<input id="complete_dir" type="hidden" value="$complete_dir" />
<div class="section">
<div class="col2">
<h3>$T('seriesSorting')</h3>
<p>
<b>$T('affectedCat')</b><br/>
<select name="tv_cat" multiple="multiple" class="multiple_cats">
<!--#for $ct in $cat_list#-->
<option value="$ct" <!--#if $ct in $tv_categories then 'selected="selected"' else ""#--> >$Tspec($ct)</option>
<!--#end for#-->
</select>
</p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<h5 class="darkred nomargin">$T('ft-download'): <span class="path">$complete_dir</span></h5>
</div>
<div class="field-pair alt">
<label class="config wide" for="enable_tv_sorting">$T('opt-tvsort')</label>
<input type="checkbox" name="enable_tv_sorting" id="enable_tv_sorting" value="1" <!--#if int($enable_tv_sorting) > 0 then 'checked="checked"' else ""#--> />
</div>
<div class="field-pair">
<label class="config" for="tvfoldername">$T('sortString')</label>
<input type="text" id="tvfoldername" name="tv_sort_string" value="$tv_sort_string" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair alt">
<label class="config">$T('presetSort')</label>
<div class="presets float-left">
<input type="button" onclick="tvSet('%sn/Season %s/%sn - %sx%0e - %en.%ext')" value="$T('button-Season1x05')" />
<input type="button" onclick="tvSet('%sn/Season %s/%sn - S%0sE%0e - %en.%ext')" value="$T('button-SeasonS01E05')" /><br/>
<input type="button" onclick="tvSet('%sn/%sx%0e - %en/%sn - %sx%0e - %en.%ext')" value="$T('button-Ep1x05')" />
<input type="button" onclick="tvSet('%sn/S%0sE%0e - %en/%sn - S%0sE%0e - %en.%ext')" value="$T('button-EpS01E05')" />
</div>
</div>
<div id="previewtv" class="example">
<div class="field-pair">
<label class="config" for="tvsamplename">Test Data</label>
<input type="text" id="tvsamplename" name="tvsamplename" placeholder="$T('show-name') S01E05 - $T('ep-name') [DTS]" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair">
<label class="config">$T('sortResult')</label>
<span class="desc path" id="previewtv-result">&nbsp;</span>
</div>
</div>
<div class="field-pair">
<label class="config">$T('sort-legenda')</label>
<input type="button" value="$T('sort-legenda')" onclick="jQuery(this).hide(); jQuery('#Key1').show();" />
<table id="Key1" class="Key">
<thead>
<tr>
<th class="align-right">$T('sort-meaning')</th>
<th>$T('sort-pattern')</th>
<th>$T('sort-result')</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-right"><b>$T('show-name'):</b></td>
<td>%sn</td>
<td>$T('show-sp-name')</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%s.n</td>
<td>$T('show-dot-name')</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>%s_n</td>
<td>$T('show-us-name')</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('show-name'):</b></td>
<td>%sN</td>
<td>$T('show-sp-name') ($T('case-adjusted'))</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>%s.N</td>
<td>$T('show-dot-name') ($T('case-adjusted'))</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%s_N</td>
<td>$T('show-us-name') ($T('case-adjusted'))</td>
</tr>
<tr>
<td class="align-right"><b>$T('show-seasonNum'):</b></td>
<td>%s</td>
<td>1</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%0s</td>
<td>01</td>
</tr>
<tr>
<td class="align-right"><b>$T('show-epNum'):</b></td>
<td>%e</td>
<td>5</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%0e</td>
<td>05</td>
</tr>
<tr>
<td class="align-right"><b>$T('ep-name'):</b></td>
<td>%en</td>
<td>$T('ep-sp-name')</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%e.n</td>
<td>$T('ep-dot-name')</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>%e_n</td>
<td>$T('ep-us-name')</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('fileExt'):</b></td>
<td>%ext</td>
<td>avi</td>
</tr>
<tr>
<td class="align-right"><b>$T('orgFilename'):</b></td>
<td>%fn</td>
<td>$T("sort-File")</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('orgDirname'):</b></td>
<td>%dn</td>
<td>$T("sort-Folder")</td>
</tr>
<tr>
<td class="align-right"><b>$T('lowercase'):</b></td>
<td>{$T('TEXT')}</td>
<td>$T('text')</td>
</tr>
</tbody>
</table>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('genericSort')</h3>
<p>
<b>$T('affectedCat')</b><br/>
<select name="movie_cat" multiple="multiple" class="multiple_cats">
<!--#for $ct in $cat_list#-->
<option value="$ct" <!--#if $ct in $movie_categories then 'selected="selected"' else ""#--> >$Tspec($ct)</option>
<!--#end for#-->
</select>
</p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<h5 class="darkred nomargin">$T('ft-download'): <span class="path">$complete_dir</span></h5>
</div>
<div class="field-pair alt">
<label class="config wide" for="enable_movie_sorting">$T('opt-movieSort')</label>
<input type="checkbox" name="enable_movie_sorting" id="enable_movie_sorting" value="1" <!--#if int($enable_movie_sorting) > 0 then 'checked="checked"' else ""#--> />
</div>
<div class="field-pair">
<label class="config wide" for="movie_extra_folder">$T('opt-movieExtra')</label>
<input type="checkbox" name="movie_extra_folder" id="movie_extra_folder" value="1" <!--#if int($movie_extra_folder) > 0 then 'checked="checked"' else ""#--> />
</div>
<div class="field-pair alt">
<label class="config" for="moviefoldername">$T('sortString')</label>
<input type="text" name="movie_sort_string" id="moviefoldername" value="$movie_sort_string" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair">
<label class="config" for="movieextra">$T('multiPartLabel')</label>
<input type="text" name="movie_sort_extra" id="movieextra" value="$movie_sort_extra" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair alt">
<label class="config">$T('presetSort')</label>
<div class="presets float-left">
<input type="button" onclick="movieSet('%title (%y)/%title (%y).%ext',' CD%1');movieExtraFolder(false)" value="$T('button-inFolders')" />
<input type="button" onclick="movieSet('%title (%y).%ext',' CD%1');movieExtraFolder(true)" value="$T('button-noFolders')" />
<input type="button" onclick="movieSet('%0decade/%title (%y).%ext',' CD%1');movieExtraFolder(true)" value="Decades 1" />
</div>
</div>
<div id="previewmovie" class="example">
<div class="field-pair">
<label class="config" for="moviesamplename">Test Data</label>
<input type="text" id="moviesamplename" name="moviesamplename" placeholder="$T('movie-sp-name') (2009)" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair">
<label class="config">$T('sortResult')</label>
<span class="desc path" id="previewmovie-result">&nbsp;</span>
</div>
</div>
<div class="field-pair">
<label class="config">$T('sort-legenda')</label>
<input type="button" value="$T('sort-legenda')" onclick="jQuery(this).hide(); jQuery('#Key2').show();" />
<table id="Key2" class="Key">
<thead>
<tr>
<th class="align-right">$T('sort-meaning')</th>
<th>$T('sort-pattern')</th>
<th>$T('sort-result')</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-right"><b>$T('sort-title'):</b></td>
<td>%title</td>
<td>$T('movie-sp-name')</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%.title</td>
<td>$T('movie-dot-name')</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>%_title</td>
<td>$T('movie-us-name')</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('year'):</b></td>
<td>%y</td>
<td>2009</td>
</tr>
<tr>
<td class="align-right"><b>$T('extension'):</b></td>
<td>%ext</td>
<td>avi</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('decade'):</b></td>
<td>%decade</td>
<td>00</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>%0decade</td>
<td>2000</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('orgFilename'):</b></td>
<td>%fn</td>
<td>$T('sort-File')</td>
</tr>
<tr>
<td class="align-right"><b>$T('orgDirname'):</b></td>
<td>%dn</td>
<td>$T("sort-Folder")</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('lowercase'):</b></td>
<td>{$T('TEXT')}</td>
<td>$T('text')</td>
</tr>
</tbody>
<tbody>
<tr>
<th class="align-right"><b>$T('multiPartLabel')</b></th>
<th>$T('sort-pattern')</th>
<th>$T('sort-result')</th>
</tr>
</tbody>
<tbody>
<tr>
<td class="align-right"><b>$T('partNumber'):</b></td>
<td>%1</td>
<td>1</td>
</tr>
</tbody>
</table>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('dateSorting')</h3>
<p>
<b>$T('affectedCat')</b><br/>
<select name="date_cat" multiple="multiple" class="multiple_cats">
<!--#for $ct in $cat_list#-->
<option value="$ct" <!--#if $ct in $date_categories then 'selected="selected"' else ""#--> >$Tspec($ct)</option>
<!--#end for#-->
</select>
</p>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<h5 class="darkred nomargin">$T('ft-download'): <span class="path">$complete_dir</span></h5>
</div>
<div class="field-pair alt">
<label class="config wide" for="enable_date_sorting">$T('opt-dateSort')</label>
<input type="checkbox" name="enable_date_sorting" id="enable_date_sorting" value="1" <!--#if int($enable_date_sorting) > 0 then 'checked="checked"' else ""#--> />
</div>
<div class="field-pair">
<label class="config" for="datefoldername">$T('sortString')</label>
<input type="text" name="date_sort_string" id="datefoldername" value="$date_sort_string" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair alt">
<label class="config">$T('presetSort')</label>
<div class="presets float-left">
<input type="button" onclick="dateSet('%t/%t - %y-%0m-%0d - %desc.%ext')" value="$T('button-ShowNameF')" />
<input type="button" onclick="dateSet('%y-%0m/%t - %y-%0m-%0d - %desc.%ext')" value="$T('button-YMF')" />
<input type="button" onclick="dateSet('%y-%0m-%0d/%t - %y-%0m-%0d - %desc.%ext')" value="$T('button-DailyF')" />
</div>
</div>
<div id="previewdate" class="example">
<div class="field-pair">
<label class="config" for="datesamplename">Test Data</label>
<input type="text" id="datesamplename" name="datesamplename" placeholder="$T('show-name') 2009-01-02" size="50" />
<input type="button" value="$T('button-clear')" class="clearBtn" />
</div>
<div class="field-pair">
<label class="config">$T('sortResult')</label>
<span class="desc path" id="previewdate-result">&nbsp;</span>
</div>
</div>
<div class="field-pair">
<label class="config">$T('sort-legenda')</label>
<input type="button" value="$T('sort-legenda')" onclick="jQuery(this).hide(); jQuery('#Key3').show();" />
<table id="Key3" class="Key">
<thead>
<tr>
<th class="align-right">$T('sort-meaning')</th>
<th>$T('sort-pattern')</th>
<th>$T('sort-result')</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-right"><b>$T('show-name'):</b></td>
<td>%t</td>
<td>$T('show-sp-name')</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%.t</td>
<td>$T('show-dot-name')</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>%_t</td>
<td>$T('show-us-name')</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('year'):</b></td>
<td>%y</td>
<td>2009</td>
</tr>
<tr>
<td class="align-right"><b>$T('month'):</b></td>
<td>%m</td>
<td>1</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%0m</td>
<td>01</td>
</tr>
<tr>
<td class="align-right"><b>$T('day-of-month'):</b></td>
<td>%d</td>
<td>2</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%0d</td>
<td>02</td>
</tr>
<tr>
<td class="align-right"><b>$T('decade'):</b></td>
<td>%decade</td>
<td>00</td>
</tr>
<tr class="even">
<td>&nbsp;</td>
<td>%0decade</td>
<td>2000</td>
</tr>
<tr>
<td class="align-right"><b>$T('orgFilename'):</b></td>
<td>%fn</td>
<td>$T('sort-File')</td>
</tr>
<tr class="even">
<td class="align-right"><b>$T('lowercase'):</b></td>
<td>{$T('TEXT')}</td>
<td>$T('text')</td>
</tr>
</tbody>
</table>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<script>
// http://stackoverflow.com/questions/2219924/idiomatic-jquery-delayed-event-only-after-a-short-pause-in-typing-e-g-timew
var typewatch = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
}
})();
function tvSet(val) {
\$('#tvfoldername').val(val);
new_previewtv();
}
function movieSet(val, val2) {
\$('#moviefoldername').val(val);
\$('#movieextra').val(val2);
new_previewmovie();
}
function movieExtraFolder(value) {
\$('#movie_extra_folder').attr("checked", value);
}
function dateSet(val) {
\$('#datefoldername').val(val);
new_previewdate();
}
function new_previewtv() {
var \$tvsortstring = \$('#tvfoldername').val();
if(\$tvsortstring.length > 2) {
typewatch(function () {
\$('#previewtv').show();
\$('#previewtv-result').addClass("loading");
\$.ajax({
type: "GET",
url: "../../tapi",
data: {mode:'eval_sort', value: 'series', name: \$('#tvsamplename').val(), title: \$tvsortstring, apikey: '$session', output: 'json' },
success: function(data){
\$('#previewtv-result').removeClass("loading failure").html(data.result);
},
error: function(data){ \$('#previewtv-result').removeClass("loading").addClass("failure").html('need more information to process'); }
});
}, 500);
}
else
\$('#previewtv').hide();
}
function new_previewmovie() {
var \$moviesortstring = \$('#moviefoldername').val();
if(\$moviesortstring.length > 2) {
typewatch(function () {
\$('#previewmovie').show();
\$('#previewmovie-result').addClass("loading");
\$.ajax({
type: "GET",
url: "../../tapi",
data: {mode:'eval_sort', value: 'generic', name: \$('#moviesamplename').val(), title: \$moviesortstring, movieextra: \$('#movieextra').val(), apikey: '$session', output: 'json' },
success: function(data){
\$('#previewmovie-result').removeClass("loading failure").html(data.result);
},
error: function(data){ \$('#previewmovie-result').removeClass("loading").addClass("failure").html('need more information to process'); }
});
}, 500);
}
else
\$('#previewmovie').hide();
}
function new_previewdate() {
var \$datesortstring = \$('#datefoldername').val();
if(\$datesortstring.length > 2) {
typewatch(function () {
\$('#previewdate').show();
\$('#previewdate-result').addClass("loading");
\$.ajax({
type: "GET",
url: "../../tapi",
data: {mode:'eval_sort', value: 'date', name: \$('#datesamplename').val(), title: \$datesortstring, apikey: '$session', output: 'json' },
success: function(data){
\$('#previewdate-result').removeClass("loading failure").html(data.result);
},
error: function(data){ \$('#previewdate-result').removeClass("loading").addClass("failure").html('need more information to process'); }
});
}, 500);
}
else
\$('#previewdate').hide();
}
</script>
<script>
\$(document).ready(function(){
new_previewtv();
new_previewmovie();
new_previewdate();
\$('#tvfoldername, #tvsamplename').bind("keyup focus", new_previewtv);
\$('#moviefoldername, #movieextra, #moviesamplename').bind("keyup focus", new_previewmovie);
\$('#datefoldername, #datesamplename').bind("keyup focus", new_previewdate);
\$('.clearBtn').click(function(){
\$(this).prev().val('').focus();
});
});
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,59 @@
<!--#set global $pane="Special"#-->
<!--#set global $help_uri="configure+special-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSpecial" method="post" name="fullform" id="fullform">
<input type="hidden" id="session" name="session" value="$session" />
<div class="padTable">
<h3 class="darkred nomargin">$T('explain-special')</h3>
</div>
<div class="section">
<div class="col2">
<h3>$T('sptag-boolean')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<!--#set $odd = False#-->
<!--#for $option in $switches#-->
<!--#set $odd = not $odd#-->
<div class="field-pair <!--#if $odd then "alt" else ""#-->">
<label class="config wide" for="$option[0]">$option[0] ( <span class="path"><!--#if $option[2] then $T('on') else $T('off')#--></span> )</label>
<input type="checkbox" name="$option[0]" id="$option[0]" value="1" <!--#if int($option[1]) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">&nbsp;</span>
</div>
<!--#end for#-->
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('sptag-entries')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<!--#set $odd = False#-->
<!--#for $option in $entries#-->
<!--#set $odd = not $odd#-->
<div class="field-pair <!--#if $odd then "alt" else ""#-->">
<label class="config narrow" for="$option[0]">$option[0] (&nbsp;<span class="path">$option[2]</span>&nbsp;)</label>
<input type="text" name="$option[0]" id="$option[0]" value="$option[1]" />
</div>
<!--#end for#-->
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,315 @@
<!--#set global $pane="Switches"#-->
<!--#set global $help_uri="configure-switches-0-7"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSwitches" method="post" name="fullform" id="fullform">
<input type="hidden" id="session" name="session" value="$session" />
<div class="section">
<div class="col2">
<h3>$T('swtag-general')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="check_new_rel">$T('opt-check_new_rel')</label>
<select name="check_new_rel" id="check_new_rel">
<option value="0" <!--#if $check_new_rel == 0 then 'selected="selected" class="selected"' else ""#--> >$T('off')</option>
<option value="1" <!--#if $check_new_rel == 1 then 'selected="selected" class="selected"' else ""#--> >$T('on')</option>
<option value="2" <!--#if $check_new_rel == 2 then 'selected="selected" class="selected"' else ""#--> >$T('also-test')</option>
</select>
<span class="desc">$T('explain-check_new_rel')</span>
</div>
<div class="field-pair">
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-auto_browser')</span>
</div>
<div class="field-pair alt <!--#if not $have_ampm then "disabled" else "" #-->">
<label class="config" for="ampm">$T('opt-ampm')</label>
<input type="checkbox" name="ampm" id="ampm" value="1" <!--#if int($ampm) > 0 then 'checked="checked"' else ""#--> <!--#if not $have_ampm then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-ampm')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('swtag-server')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="max_art_tries">$T('opt-max_art_tries')</label>
<input type="number" name="max_art_tries" id="max_art_tries" value="$max_art_tries" size="8" min="2" />
<span class="desc">$T('explain-max_art_tries')</span>
</div>
<div class="field-pair">
<label class="config" for="max_art_opt">$T('opt-max_art_opt')</label>
<input type="checkbox" name="max_art_opt" id="max_art_opt" value="1" <!--#if int($max_art_opt) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-max_art_opt')</span>
</div>
<div class="field-pair alt">
<label class="config" for="auto_disconnect">$T('opt-auto_disconnect')</label>
<input type="checkbox" name="auto_disconnect" id="auto_disconnect" value="1" <!--#if int($auto_disconnect) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-auto_disconnect')</span>
</div>
<div class="field-pair">
<label class="config" for="send_group">$T('opt-send_group')</label>
<input type="checkbox" name="send_group" id="send_group" value="1" <!--#if int($send_group) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-send_group')</span>
</div>
<div class="field-pair alt">
<label class="config" for="ssl_type">$T('opt-ssl_type')</label>
<select name="ssl_type" id="ssl_type">
<option value="v23" <!--#if $ssl_type == "v23" then 'selected="selected" class="selected"' else ""#--> >V23</option>
<option value="v2" <!--#if $ssl_type == "v2" then 'selected="selected" class="selected"' else ""#--> >V2</option>
<option value="v3" <!--#if $ssl_type == "v3" then 'selected="selected" class="selected"' else ""#--> >V3</option>
</select>
<span class="desc">$T('explain-ssl_type')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('swtag-queue')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<label class="config" for="fail_hopeless">$T('opt-fail_hopeless')</label>
<input type="checkbox" name="fail_hopeless" id="fail_hopeless" value="1" <!--#if int($fail_hopeless) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-fail_hopeless')</span>
</div>
<div class="field-pair alt">
<label class="config" for="pre_check">$T('opt-pre_check')</label>
<input type="checkbox" name="pre_check" id="pre_check" value="1" <!--#if int($pre_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-pre_check')</span>
</div>
<div class="field-pair">
<label class="config" for="no_dupes">$T('opt-no_dupes')</label>
<select name="no_dupes" id="no_dupes">
<option value="0" <!--#if int($no_dupes) == 0 then 'selected="selected" class="selected"' else ""#--> >$T('nodupes-off')</option>
<option value="1" <!--#if int($no_dupes) == 1 then 'selected="selected" class="selected"' else ""#--> >$T('nodupes-ignore')</option>
<option value="2" <!--#if int($no_dupes) == 2 then 'selected="selected" class="selected"' else ""#--> >$T('nodupes-pause')</option>
</select>
<span class="desc">$T('explain-no_dupes')</span>
</div>
<div class="field-pair alt">
<label class="config" for="pause_on_post_processing">$T('opt-pause_on_post_processing')</label>
<input type="checkbox" name="pause_on_post_processing" id="pause_on_post_processing" value="1" <!--#if int($pause_on_post_processing) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-pause_on_post_processing')</span>
</div>
<div class="field-pair">
<label class="config" for="pause_on_pwrar">$T('opt-pause_on_pwrar')</label>
<select name="pause_on_pwrar" id="pause_on_pwrar">
<option value="0" <!--#if int($pause_on_pwrar) == 0 then 'selected="selected" class="selected"' else ""#--> >$T('nodupes-off')</option>
<option value="1" <!--#if int($pause_on_pwrar) == 1 then 'selected="selected" class="selected"' else ""#--> >$T('nodupes-pause')</option>
<option value="2" <!--#if int($pause_on_pwrar) == 2 then 'selected="selected" class="selected"' else ""#--> >$T('abort')</option>
</select>
<span class="desc">$T('explain-pause_on_pwrar')</span>
</div>
<div class="field-pair alt">
<label class="config" for="top_only">$T('opt-top_only')</label>
<input type="checkbox" name="top_only" id="top_only" value="1" <!--#if int($top_only) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-top_only')</span>
</div>
<div class="field-pair">
<label class="config" for="auto_sort">$T('opt-auto_sort')</label>
<input type="checkbox" name="auto_sort" id="auto_sort" value="1" <!--#if int($auto_sort) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-auto_sort')</span>
</div>
<div class="field-pair alt">
<label class="config" for="pre_script">$T('opt-pre_script')</label>
<select name="pre_script" id="pre_script">
<!--#for $sc in $script_list#-->
<!--#if $sc.lower() == $pre_script.lower()#-->
<option value="$sc" selected="selected" class="selected">$Tspec($sc)</option>
<!--#else#-->
<option value="$sc">$Tspec($sc)</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-pre_script')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('swtag-pp')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="ignore_samples">$T('opt-ignore_samples')</label>
<select name="ignore_samples" id="ignore_samples">
<option value="0" <!--#if int($ignore_samples) == 0 then 'selected="selected" class="selected"' else ""#--> >$T('igsam-off')</option>
<option value="1" <!--#if int($ignore_samples) == 1 then 'selected="selected" class="selected"' else ""#--> >$T('igsam-del')</option>
<option value="2" <!--#if int($ignore_samples) == 2 then 'selected="selected" class="selected"' else ""#--> >$T('igsam-not')</option>
</select>
<span class="desc">$T('explain-ignore_samples')</span>
</div>
<div class="field-pair">
<label class="config" for="quick_check">$T('opt-quick_check')</label>
<input type="checkbox" name="quick_check" id="quick_check" value="1" <!--#if int($quick_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-quick_check')</span>
</div>
<div class="field-pair alt">
<label class="config" for="enable_unrar">$T('opt-enable_unrar')</label>
<input type="checkbox" name="enable_unrar" id="enable_unrar" value="1" <!--#if int($enable_unrar) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-enable_unrar')</span>
</div>
<div class="field-pair">
<label class="config" for="enable_unzip">$T('opt-enable_unzip')</label>
<input type="checkbox" name="enable_unzip" id="enable_unzip" value="1" <!--#if int($enable_unzip) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-enable_unzip')</span>
</div>
<div class="field-pair alt">
<label class="config" for="enable_filejoin">$T('opt-enable_filejoin')</label>
<input type="checkbox" name="enable_filejoin" id="enable_filejoin" value="1" <!--#if int($enable_filejoin) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-enable_filejoin')</span>
</div>
<div class="field-pair">
<label class="config" for="enable_tsjoin">$T('opt-enable_tsjoin')</label>
<input type="checkbox" name="enable_tsjoin" id="enable_tsjoin" value="1" <!--#if int($enable_tsjoin) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-ts_join')</span>
</div>
<div class="field-pair alt">
<label class="config" for="enable_par_cleanup">$T('opt-enable_par_cleanup')</label>
<input type="checkbox" name="enable_par_cleanup" id="enable_par_cleanup" value="1" <!--#if int($enable_par_cleanup) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-enable_par_cleanup')</span>
</div>
<div class="field-pair">
<label class="config" for="fail_on_crc">$T('opt-fail_on_crc')</label>
<input type="checkbox" name="fail_on_crc" id="fail_on_crc" value="1" <!--#if int($fail_on_crc) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-fail_on_crc')</span>
</div>
<div class="field-pair alt">
<label class="config" for="safe_postproc">$T('opt-safe_postproc')</label>
<input type="checkbox" name="safe_postproc" id="safe_postproc" value="1" <!--#if int($safe_postproc) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-safe_postproc')</span>
</div>
<div class="field-pair">
<label class="config" for="sfv_check">$T('opt-sfv_check')</label>
<input type="checkbox" name="sfv_check" id="sfv_check" value="1" <!--#if int($sfv_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-sfv_check')</span>
</div>
<div class="field-pair alt">
<label class="config" for="unpack_check">$T('opt-unpack_check')</label>
<input type="checkbox" name="unpack_check" id="unpack_check" value="1" <!--#if int($unpack_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-unpack_check')</span>
</div>
<div class="field-pair <!--#if not $nt then "disabled" else "" #-->">
<label class="config" for="par2_multicore">$T('opt-par2_multicore')</label>
<input type="checkbox" name="par2_multicore" id="par2_multicore" value="1" <!--#if int($par2_multicore) > 0 then 'checked="checked"' else ""#--> <!--#if not $nt then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-par2_multicore')</span>
</div>
<div class="field-pair alt">
<label class="config" for="par_option">$T('opt-par_option')</label>
<input type="text" name="par_option" id="par_option" value="$par_option" size="20" />
<span class="desc">$T('explain-par_option')</span>
</div>
<div class="field-pair <!--#if not $have_nice then "disabled" else "" #-->">
<label class="config" for="nice">$T('opt-nice')</label>
<input type="text" name="nice" id="nice" value="$nice" size="20" <!--#if not $have_nice then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-nice')</span>
</div>
<div class="field-pair alt <!--#if not $have_ionice then "disabled" else "" #-->">
<label class="config" for="ionice">$T('opt-ionice')</label>
<input type="text" name="ionice" id="ionice" value="$ionice" size="20" <!--#if not $have_ionice then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-ionice')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('swtag-naming')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="folder_rename">$T('opt-folder_rename')</label>
<input type="checkbox" name="folder_rename" id="folder_rename" value="1" <!--#if int($folder_rename) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-folder_rename')</span>
</div>
<div class="field-pair">
<label class="config" for="replace_spaces">$T('opt-replace_spaces')</label>
<input type="checkbox" name="replace_spaces" id="replace_spaces" value="1" <!--#if int($replace_spaces) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-replace_spaces')</span>
</div>
<div class="field-pair alt">
<label class="config" for="replace_dots">$T('opt-replace_dots')</label>
<input type="checkbox" name="replace_dots" id="replace_dots" value="1" <!--#if int($replace_dots) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-replace_dots')</span>
</div>
<div class="field-pair">
<label class="config" for="replace_illegal">$T('opt-replace_illegal')</label>
<input type="checkbox" name="replace_illegal" id="replace_illegal" value="1" <!--#if int($replace_illegal) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-replace_illegal')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="section">
<div class="col2">
<h3>$T('swtag-quota')</h3>
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair alt">
<label class="config" for="quota_size">$T('opt-quota_size')</label>
<input type="text" name="quota_size" id="quota_size" value="$quota_size" size="8" />
<span class="desc">$T('explain-quota_size')</span>
</div>
<div class="field-pair">
<label class="config" for="quota_period">$T('opt-quota_period')</label>
<select name="quota_period" id="quota_period">
<option value="d" <!--#if $quota_period == "d" then 'selected="selected" class="selected"' else ""#--> >$T('day').capitalize()</option>
<option value="w" <!--#if $quota_period == "w" then 'selected="selected" class="selected"' else ""#--> >$T('week').capitalize()</option>
<option value="m" <!--#if $quota_period == "m" then 'selected="selected" class="selected"' else ""#--> >$T('month').capitalize()</option>
<option value="x" <!--#if $quota_period == "x" then 'selected="selected" class="selected"' else ""#--> >$T('manual').capitalize()</option>
</select>
<span class="desc">$T('explain-quota_period')</span>
</div>
<div class="field-pair alt">
<label class="config" for="quota_day">$T('opt-quota_day')</label>
<input type="text" name="quota_day" id="quota_day" value="$quota_day" size="20" />
<span class="desc">$T('explain-quota_day')</span>
</div>
<div class="field-pair">
<label class="config" for="quota_resume">$T('opt-quota_resume')</label>
<input type="checkbox" name="quota_resume" id="quota_resume" value="1" <!--#if int($quota_resume) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-quota_resume')</span>
</div>
<div class="field-pair">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
</div>
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
<div class="padding alt">
<input type="submit" value="$T('button-saveChanges')" class="saveButton" />
<input type="button" value="$T('button-restart') SABnzbd" class="sabnzbd_restart" />
</div>
</form>
</div><!-- /colmask -->
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -0,0 +1,2 @@
/* This file was intentionally left blank and is only needed for 'skin' detection routine */
/* https://github.com/thezoggy/sabnzbd-uni_Config */

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

File diff suppressed because one or more lines are too long

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

View File

File diff suppressed because one or more lines are too long

View File

@@ -9,7 +9,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SABnzbd $version - $T('queued'): $mbleft $T('MB')</title>
<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="${path}rss?mode=history"/>
@@ -126,8 +126,10 @@
<div class="config_sprite_container sprite_config_nav_scheduling">$T('Plush-cmenu-scheduling')</div></a></li>
<li><a class="#if $pane=="Email"#nav_active#end if#" id="config_nav_email" href="${path}config/notify/">
<div class="config_sprite_container sprite_config_nav_email">$T('cmenu-notif')</div></a></li>
<!--#if 0#-->
<li><a class="#if $pane=="Index Sites"#nav_active#end if#" id="config_nav_index_sites" href="${path}config/indexers/">
<div class="config_sprite_container sprite_config_nav_indexsites">$T('cmenu-newzbin')</div></a></li>
<!--#end if#-->
<li><a class="#if $pane=="Categories"#nav_active#end if#" id="config_nav_categories" href="${path}config/categories/">
<div class="config_sprite_container sprite_config_nav_categories">$T('cmenu-cat')</div></a></li>
<li><a class="#if $pane=="Sorting"#nav_active#end if#" id="config_nav_sorting" href="${path}config/sorting/">

View File

@@ -10,7 +10,7 @@
</table>
<div class="sabnzbd_logo main_sprite_container sprite_sabnzbdplus_logo"></div>
<p><strong>SABnzbd $T('version'):</strong> $version</p>
<p><small>Copyright (C) 2008-2012, The SABnzbd Team &lt;<a href="mailto:team@sabnzbd.org">team@sabnzbd.org</a>&gt;</small></p>
<p><small>Copyright (C) 2008-2012, The SABnzbd Team &lt;team@sabnzbd.org&gt;</small></p>
<p><small>$T('yourRights')</small></p>
</div>

View File

@@ -43,90 +43,6 @@
</fieldset>
</div><!-- /component-group1 -->
<div id="core-component-group2" class="component-group clearfix">
<div class="component-group-desc">
<h3>Newzbin $T('accountInfo')</h3>
<p>$T('explain-newzbin')</p>
</div>
<fieldset class="component-group-list">
<div class="field-pair">
<label class="nocheck clearfix" for="username_newzbin">
<span class="component-title">$T('opt-username_newzbin')</span>
<input type="text" name="username_newzbin" id="username_newzbin" value="$username_newzbin"/>
</label>
<label class="nocheck clearfix">
<span class="component-title">&nbsp;</span>
<span class="component-desc">$T('explain-username_newzbin')</span>
</label>
</div>
<div class="field-pair alt">
<label class="nocheck clearfix" for="password_newzbin">
<span class="component-title">$T('opt-password_newzbin')</span>
<input type="password" name="password_newzbin" id="password_newzbin" value="$password_newzbin"/>
</label>
<label class="nocheck clearfix">
<span class="component-title">&nbsp;</span>
<span class="component-desc">$T('explain-password_newzbin')</span>
</label>
</div>
</fieldset>
</div><!-- /component-group2 -->
<div id="core-component-group3" class="component-group clearfix">
<div class="component-group-desc">
<h3>Newzbin $T('newzbinBookmarks')</h3>
<p>
<input type="button" class="juiButton" id="getBookmarks" value="$T('link-getBookmarks')" />
<br/><br/>
<!--#if $bookmarks_list#-->
<input type="button" class="juiButton" id="hideBookmarks" value="$T('link-HideBM')" />
<!--#else#-->
<input type="button" class="juiButton" id="showBookmarks" value="$T('link-ShowBM')" />
<!--#end if#-->
</p>
</div>
<fieldset class="component-group-list">
<div class="field-pair">
<input type="checkbox" name="newzbin_bookmarks" id="newzbin_bookmarks" value="1" <!--#if $newzbin_bookmarks > 0 then "checked=1" else ""#--> />
<label class="clearfix" for="newzbin_bookmarks">
<span class="component-title">$T('opt-newzbin_bookmarks')</span>
<span class="component-desc">$T('explain-newzbin_bookmarks')</span>
</label>
</div>
<div class="field-pair alt">
<input type="checkbox" name="newzbin_unbookmark" id="newzbin_unbookmark" value="1" <!--#if $newzbin_unbookmark > 0 then "checked=1" else ""#--> />
<label class="clearfix" for="newzbin_unbookmark">
<span class="component-title">$T('opt-newzbin_unbookmark')</span>
<span class="component-desc">$T('explain-newzbin_unbookmark')</span>
</label>
</div>
<div class="field-pair">
<label class="nocheck clearfix" for="bookmark_rate">
<span class="component-title">$T('opt-bookmark_rate')</span>
<input type="text" name="bookmark_rate" id="bookmark_rate" size="6" value="$bookmark_rate"/>
</label>
<label class="nocheck clearfix">
<span class="component-title">&nbsp;</span>
<span class="component-desc">$T('explain-bookmark_rate')</span>
</label>
</div>
</fieldset>
</div><!-- /component-group3 -->
<!--#if $bookmarks_list#-->
<div id="core-component-group4" class="component-group clearfix">
<div class="component-group-desc">
<h3>Newzbin $T('accountInfo')</h3>
<p>$T('explain-newzbin')</p>
</div>
<fieldset class="component-group-list">
<!--#for $msgid in $bookmarks_list#-->
<a href="https://$newzbin_url/browse/post/$msgid/" target="_blank">$msgid</a><br/>
<!--#end for#-->
</fieldset>
</div><!-- /component-group4 -->
<!--#end if#-->
<div class="component-group-last clearfix">
<div class="component-group-desc">
<h3>&nbsp;</h3>

View File

@@ -174,6 +174,7 @@ $T('explain-RSS')
<table class="rssTable">
<tr>
<th>$T('Plush-rss-delete')</th>
<th>&nbsp;</th>
<th>$T('rss-order')</th>
<th>$T('rss-type')</th>
<th>$T('rss-filter')</th>
@@ -187,6 +188,7 @@ $T('explain-RSS')
<form action="upd_rss_filter" method="get">
<tr class="odd">
<td></td>
<td><input type="checkbox" name="enabled" value="1" checked="checked" /></td>
<td></td>
<td>
<select name="filter_type">
@@ -255,7 +257,10 @@ $T('explain-RSS')
</td>
<form action="upd_rss_filter" method="get">
<td>
<td>
<input type="checkbox" name="enabled" value="1" <!--#if $filter[6] == '1' then 'checked="checked"' else ""#--> />
</td>
<td>
<input type="text" size="3" name="new_index" value=$fnum>
</td>
<td>
@@ -310,6 +315,7 @@ $T('explain-RSS')
<input type="hidden" name="feed" value="$feed"/>
<input type="hidden" name="session" value="$session">
<input type="submit" class="juiButton" value="$T('button-save')"/>
<!--#if not $rss[$feed].filter_states[$fnum]#-->&nbsp;&nbsp;$T('Incorrect filter')<!--#end if#-->
</td>
</form>
</tr>

View File

@@ -36,18 +36,15 @@ else:
</label>
</div>
<div class="field-pair alt">
<label class="nocheck clearfix" for="dayofweek">
<label class="nocheck clearfix" for="daysofweek">
<span class="component-title">$T('sch-frequency')</span>
<select name="dayofweek" id="dayofweek">
<option value="*" selected>$T('daily')</option>
<option value="1">$T('monday')</option>
<option value="2">$T('tuesday')</option>
<option value="3">$T('wednesday')</option>
<option value="4">$T('thursday')</option>
<option value="5">$T('friday')</option>
<option value="6">$T('saturday')</option>
<option value="7">$T('sunday')</option>
</select>
<input type="checkbox" name="daysofweek" value="1">$T('monday')<br/>
<input type="checkbox" name="daysofweek" value="2">$T('tuesday')<br/>
<input type="checkbox" name="daysofweek" value="3">$T('wednesday')<br/>
<input type="checkbox" name="daysofweek" value="4">$T('thursday')<br/>
<input type="checkbox" name="daysofweek" value="5">$T('friday')<br/>
<input type="checkbox" name="daysofweek" value="6">$T('saturday')<br/>
<input type="checkbox" name="daysofweek" value="7">$T('sunday')<br/>
</label>
</div>
<div class="field-pair">

View File

@@ -46,7 +46,7 @@
<div class="field-pair alt">
<label class="nocheck clearfix" for="password">
<span class="component-title">$T('srv-password')</span>
<input type="text" size="25" name="password"/>
<input type="password" size="25" name="password"/>
</label>
</div>
<div class="field-pair">
@@ -156,7 +156,7 @@
<div class="field-pair alt">
<label class="nocheck clearfix" for="password">
<span class="component-title">$T('srv-password')</span>
<input type="text" size="25" name="password" value="$servers[$server]['password']" />
<input type="password" size="25" name="password" value="$servers[$server]['password']" />
</label>
</div>
<div class="field-pair">

View File

@@ -26,7 +26,6 @@
<a class="sf-with-ul">$T('menu-queue')</a>
<ul>
<!--#if $have_quota#--><li><a id="reset_quota_now" class="pointer">$T('link-resetQuota')</a></li><!--#end if#-->
<!--#if $varExists('newzbinDetails')#--><li><a id="get_bookmarks_now" class="pointer">$T('link-getBookmarks')</a></li><!--#end if#-->
<!--#if $have_rss_defined#--><li><a id="get_rss_now" class="pointer">$T('button-rssNow')</a></li><!--#end if#-->
<!--#if $have_watched_dir#--><li><a id="get_watched_now" class="pointer">$T('sch-scan_folder')</a></li><!--#end if#-->
<li><a id="topmenu_toggle" class="pointer">$T('Plush-topMenu')</a></li>

View File

@@ -56,7 +56,7 @@
</td>
<td class="download-title">
<a href="nzb/$slot.nzo_id/" title="$T('status'): $T('post-'+$slot.status)<br/>$T('nzo-age'): $slot.avg_age<br/><!--#if $slot.missing#-->$T('missingArt'): $slot.missing<!--#end if#-->">$slot.filename</a>
<a href="nzb/$slot.nzo_id/" title="$T('status'): $T('post-'+$slot.status)<br/>$T('nzo-age'): $slot.avg_age<br/><!--#if $slot.missing#-->$T('missingArt'): $slot.missing<!--#end if#-->">$slot.filename.replace('.', '.&#8203;').replace('_', '_&#8203;')</a>
</td>
<td>

View File

@@ -40,6 +40,7 @@ jQuery(function($){
$('#addID').click(function(){ // also works when hitting enter because of <form>
if ($('#addID_input').val()!='URL') {
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {
@@ -118,15 +119,19 @@ jQuery(function($){
// fix for touch devices -- toggle visibility
$('.sprite_q_menu_pausefor').bind('touchend', function(e) {
e.preventDefault();
if( $(this).hasClass('sprite_q_menu_pauseforsfHover') ) {
$(this).find("ul").toggle();
if (! $.browser.safari) {
e.preventDefault();
if( $(this).hasClass('sprite_q_menu_pauseforsfHover') ) {
$(this).find("ul").toggle();
}
}
});
$('.sprite_q_queue').bind('touchend', function(e) {
e.preventDefault();
if( $(this).hasClass('sprite_q_queuesfHover') ) {
$(this).find("ul").toggle();
if (! $.browser.safari) {
e.preventDefault();
if( $(this).hasClass('sprite_q_queuesfHover') ) {
$(this).find("ul").toggle();
}
}
});
@@ -154,6 +159,7 @@ jQuery(function($){
else
$('#speed-wrapper .sprite_q_menu_pausefor').removeClass('sprite_q_menu_pausefor_on');
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'config', name:'set_speedlimit', value: str, apikey: $.plush.apikey}
@@ -209,6 +215,7 @@ jQuery(function($){
else
$('.sprite_q_queue').removeClass('sprite_q_queue_on');
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'change_complete_action', value: $(this).val(), apikey: $.plush.apikey}
@@ -230,6 +237,7 @@ jQuery(function($){
value="all";
}
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'delete', value:value, del_files:del_files, apikey: $.plush.apikey},
@@ -254,6 +262,7 @@ jQuery(function($){
case 'sortSizeDesc': sort='size'; dir='desc'; break;
}
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'sort', sort: sort, dir: dir, apikey: $.plush.apikey},
@@ -268,6 +277,7 @@ jQuery(function($){
minutes = prompt($(event.target).attr('title'));
$.plush.SetQueuePauseInfo(true,minutes+':00');
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'config', name:'set_pause', value: minutes, apikey: $.plush.apikey},
@@ -278,6 +288,7 @@ jQuery(function($){
// Get Bookmarks
$('#get_bookmarks_now').click(function() {
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'newzbin', name:'get_bookmarks', apikey: $.plush.apikey},
@@ -288,6 +299,7 @@ jQuery(function($){
// Reset Quota
$('#reset_quota_now').click(function() {
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'reset_quota', apikey: $.plush.apikey},
@@ -298,6 +310,7 @@ jQuery(function($){
// Get RSS
$('#get_rss_now').click(function() {
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'rss_now', apikey: $.plush.apikey},
@@ -308,6 +321,7 @@ jQuery(function($){
// Get Watched folder
$('#get_watched_now').click(function() {
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'watched_now', apikey: $.plush.apikey},
@@ -471,6 +485,7 @@ jQuery(function($){
$('#pause_resume').removeClass('sprite_q_pause_on').addClass('sprite_q_pause');
$('#pause_int').html("");
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'resume', apikey: $.plush.apikey}
@@ -479,6 +494,7 @@ jQuery(function($){
$('#pause_resume').removeClass('sprite_q_pause').addClass('sprite_q_pause_on');
$('#pause_int').html("");
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'pause', apikey: $.plush.apikey}
@@ -522,6 +538,7 @@ jQuery(function($){
if ($(this).hasClass('sprite_ql_grip_resume_on')) {
$(this).toggleClass('sprite_ql_grip_resume_on').toggleClass('sprite_ql_grip_pause_on');
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'pause', value: pid, apikey: $.plush.apikey}
@@ -529,6 +546,7 @@ jQuery(function($){
} else {
$(this).toggleClass('sprite_ql_grip_resume_on').toggleClass('sprite_ql_grip_pause_on');
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'resume', value: pid, apikey: $.plush.apikey}
@@ -573,6 +591,7 @@ jQuery(function($){
var nzbid = $(this).parent().parent().attr('id');
var oldPos = $('#'+nzbid)[0].rowIndex + $.plush.queuecurpage * $.plush.queuePerPage;
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'priority', value: nzbid, value2: $(this).val(), apikey: $.plush.apikey},
@@ -595,6 +614,7 @@ jQuery(function($){
var val = $(this).parent().parent().attr('id');
var cval = $(this).attr('class').split(" ")[0]; // ignore added "hovering" class
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode: cval, value: val, value2: $(this).val(), apikey: $.plush.apikey},
@@ -683,6 +703,7 @@ $.plush.queueprevslots = $.plush.queuenoofslots; // for the next refresh
if (table.tBodies[0].rows[i].id == row.id) {
val2 = (i + $.plush.queuecurpage * $.plush.queuePerPage);
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'switch', value: row.id, value2: val2, apikey: $.plush.apikey},
@@ -768,6 +789,7 @@ $("a","#multiops_inputs").click(function(e){
if ($('#multi_status').val())
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:$('#multi_status').val(), value: nzo_ids, apikey: $.plush.apikey}
@@ -775,6 +797,7 @@ $("a","#multiops_inputs").click(function(e){
if ($('#multi_cat').val())
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode: 'change_cat', value: nzo_ids, value2: $('#multi_cat').val(), apikey: $.plush.apikey}
@@ -782,6 +805,7 @@ $("a","#multiops_inputs").click(function(e){
if ($('#multi_priority').val())
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'queue', name:'priority', value: nzo_ids, value2: $('#multi_priority').val(), apikey: $.plush.apikey}
@@ -789,6 +813,7 @@ $("a","#multiops_inputs").click(function(e){
if ($('#multi_pp').val())
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode: 'change_opts', value: nzo_ids, value2: $('#multi_pp').val(), apikey: $.plush.apikey}
@@ -796,6 +821,7 @@ $("a","#multiops_inputs").click(function(e){
if ($('#multi_script').val())
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode: 'change_script', value: nzo_ids, value2: $('#multi_script').val(), apikey: $.plush.apikey}
@@ -866,9 +892,10 @@ $("a","#multiops_inputs").click(function(e){
value="failed";
}
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:'history', name:'delete', value:value, del_files:del_files, apikey: $.plush.apikey},
data: {mode:'history', name:'delete', value:value, del_files:del_files, search: $('#historySearchBox').val(), apikey: $.plush.apikey},
success: function(){
$.colorbox.close();
$.plush.modalOpen=false;
@@ -955,6 +982,7 @@ $("a","#multiops_inputs").click(function(e){
$.plush.pendingHistoryRefresh = true;
$.colorbox.close();
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "tapi",
data: {mode:mode, name:'delete', value: delid, del_files: del_files, apikey: $.plush.apikey},
@@ -1081,6 +1109,7 @@ $.plush.histprevslots = $.plush.histnoofslots; // for the next refresh
// Fetch updated content from queue.tmpl
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "queue/",
data: {start: ( page * $.plush.queuePerPage ), limit: $.plush.queuePerPage},
@@ -1136,6 +1165,7 @@ $.plush.histprevslots = $.plush.histnoofslots; // for the next refresh
$.ajax({
headers: {"Cache-Control": "no-cache"},
type: "POST",
url: "history/",
data: data,
@@ -1212,12 +1242,16 @@ $.plush.histprevslots = $.plush.histnoofslots; // for the next refresh
SetQueueETAStats : function(speed,kbpersec,timeleft,eta) {
// ETA/speed stats at top of queue
if (kbpersec < 1 && $.plush.paused)
if (kbpersec < 1 || $.plush.paused) {
$('#stats_eta').html('&mdash;');
else
$('#stats_speed').html('&mdash;');
$('#time-left').attr('title','&mdash;'); // Tooltip on "time left"
}
else {
$('#stats_eta').html(timeleft);
$('#stats_speed').html(speed+"B/s");
$('#time-left').attr('title',eta); // Tooltip on "time left"
$('#stats_speed').html(speed+"B/s");
$('#time-left').attr('title',eta); // Tooltip on "time left"
}
},

View File

@@ -31,7 +31,7 @@
<!--#for $warn in $warnings#-->
<!--#set $odd = not $odd#-->
<tr class="<!--#if $odd then "odd" else "even"#-->">
<td>$warn.replace("\n","</td><td>")</td></tr>
<td>$warn.replace("\n","</td><td>", 2)</td></tr>
<!--#end for#-->
</table>
<!--#else#-->

View File

@@ -1,69 +1,4 @@
<a href="${helpuri}Configure+Indexers-0-7" id="help" target="_blank">$T('menu-help')</a><h3>Newzbin</h3>
<form id="configNewzbin" class="cmxform" autocomplete="off">
$T('explain-newzbin')<br/>
<br/>
<div class="EntryBlock">
<fieldset class="EntryFieldSet">
<legend>$T('accountInfo')</legend>
<hr />
<label class="label">$T('opt-username_newzbin'):</label>
<input type="text" name="username_newzbin" value="$username_newzbin">
<span class="tips">$T('explain-username_newzbin')</span>
<br class="clear" />
<label class="label">$T('opt-password_newzbin'):</label>
<input type="password" name="password_newzbin" value="$password_newzbin">
<span class="tips">$T('explain-password_newzbin')</span>
<br class="clear" />
</fieldset>
<fieldset class="EntryFieldSet">
<legend>$T('newzbinBookmarks')</legend>
<hr />
<label><span class="label">$T('newzbinBookmarks'):</span>
<input class="radio" type="checkbox" name="newzbin_bookmarks" value="1" <!--#if $newzbin_bookmarks > 0 then "checked=1" else ""#--> />
<span class="tips">$T('explain-newzbin_bookmarks')</span></label>
<br class="clear" />
<label><span class="label">$T('opt-newzbin_unbookmark'):</span>
<input class="radio" type="checkbox" name="newzbin_unbookmark" value="1" <!--#if $newzbin_unbookmark > 0 then "checked=1" else ""#--> />
<span class="tips">$T('explain-newzbin_unbookmark')</span></label>
<br class="clear" />
<label class="label">$T('opt-bookmark_rate'):</label>
<input type="text" name="bookmark_rate" value="$bookmark_rate">
<span class="tips">$T('explain-bookmark_rate')</span>
<br class="clear" />
</fieldset>
<a class="config" onClick="getBookmarks();">$T('link-getBookmarks')</a>
<!--#if $bookmarks_list#-->
<a class="config" onClick="lr('config/indexers/hideBookmarks');">$T('link-HideBM')</a>
<!--#else#-->
<a class="config" onClick="lr('config/indexers/showBookmarks');">$T('link-ShowBM')</a>
<!--#end if#-->
<!--#if $bookmarks_list#-->
<fieldset class="EntryFieldSet">
<legend>$T('processedBM')</legend>
<hr />
<!--#for $msgid in $bookmarks_list#-->
<a href="https://$newzbin_url/browse/post/$msgid/" target="_blank">$msgid</a>&nbsp;
<!--#end for#-->
<br class="clear" />
</fieldset>
<!--#end if#-->
</div>
<br/><hr/>
<a href="${helpuri}Configure+Indexers-0-7" id="help" target="_blank">$T('menu-help')</a>
<h3>NzbMatrix</h3><br/>
$T('explain-nzbmatrix')<br/>

View File

@@ -79,6 +79,7 @@ MochiKit.DOM.addLoadEvent(location = "../../#config-rss");
<thead>
<tr>
<th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
<th>&nbsp;</th>
<th>$T('rss-order')</th>
<th>$T('rss-type')</th>
<th>$T('rss-filter')</th>
@@ -92,6 +93,7 @@ MochiKit.DOM.addLoadEvent(location = "../../#config-rss");
<tbody>
<tr id="$feed+new_filter">
<td></td>
<td><input type="checkbox" name="enabled" value="1" checked="checked" /></td>
<td></td>
<td>
<select name="filter_type">
@@ -157,7 +159,9 @@ MochiKit.DOM.addLoadEvent(location = "../../#config-rss");
<td>
<input type="submit" value="$T('rss-delFilter')" onclick="javascript:lr('config/rss/del_rss_filter','index=$fnum&feed=$feed')" />
</td>
<td>
<input type="checkbox" name="enabled" value="1" <!--#if $filter[6] == '1' then 'checked="checked"' else ""#--> />
</td>
<td>
<input type="text" size="3" name="new_index" value=$fnum>
</td>
@@ -213,6 +217,7 @@ MochiKit.DOM.addLoadEvent(location = "../../#config-rss");
<input type="hidden" name="index" value="$fnum"/>
<input type="hidden" name="feed" value="$feed"/>
<input type="submit" value="$T('button-save')" onclick="javascript:submitconfig('config/rss/upd_rss_filter', this,'$feed+$fnum','1' )"/>
<!--#if not $rss[$feed].filter_states[$fnum]#-->&nbsp;&nbsp;$T('Incorrect filter')<!--#end if#-->
</td>
</tr>

View File

@@ -26,17 +26,14 @@ else:
<!--#end for#-->
</select>
<br class="clear" />
<label class="label">$T('sch-frequency'):</label>
<select name="dayofweek">
<option value="*" selected>$T('daily')
<option value="1">$T('monday')
<option value="2">$T('tuesday')
<option value="3">$T('wednesday')
<option value="4">$T('thursday')
<option value="5">$T('friday')
<option value="6">$T('saturday')
<option value="7">$T('sunday')
</select>
<label class="label" for="daysofweek">$T('sch-frequency'):</label>
<input type="checkbox" name="daysofweek" value="1">$T('monday')<br/>
<input type="checkbox" name="daysofweek" value="2">$T('tuesday')<br/>
<input type="checkbox" name="daysofweek" value="3">$T('wednesday')<br/>
<input type="checkbox" name="daysofweek" value="4">$T('thursday')<br/>
<input type="checkbox" name="daysofweek" value="5">$T('friday')<br/>
<input type="checkbox" name="daysofweek" value="6">$T('saturday')<br/>
<input type="checkbox" name="daysofweek" value="7">$T('sunday')<br/>
<br class="clear" />
<label class="label">$T('sch-action'):</label>
<select name="action">

View File

@@ -808,7 +808,7 @@ function lrb(url, extra, refresh)
{
method:'POST',
sendContent:values,
headers: {"Content-Type":"application/x-www-form-urlencoded"}
headers: {"Content-Type":"application/x-www-form-urlencoded", "Cache-Control": "no-cache"}
});
d.addCallback(function(d)
@@ -840,7 +840,7 @@ function lrb(url, extra, refresh)
{
method:'POST',
sendContent:values,
headers: {"Content-Type":"application/x-www-form-urlencoded"}
headers: {"Content-Type":"application/x-www-form-urlencoded", "Cache-Control": "no-cache"}
});
if (saveelement) {
@@ -1133,7 +1133,9 @@ function loadingJSON(){
<li><a class="config" href="$prefix/config/scheduling/" onclick="lr('config/scheduling/','', 0, 0);">$T('cmenu-scheduling')</a> </li>
<li><a class="config" href="$prefix/config/rss/" onclick="lr('config/rss/','', 0, 0);">$T('cmenu-rss')</a> </li>
<li><a class="config" href="$prefix/config/notify/" onclick="lr('config/notify/','', 0, 0);">$T('cmenu-notif')</a></li>
<!--#if 0#-->
<li><a class="config" href="$prefix/config/indexers/" onclick="lr('config/indexers/', '', 0, 0);">$T('cmenu-newzbin')</a></li>
<!--#end if#-->
<li><a class="config" href="$prefix/config/categories/" onclick="lr('config/categories/', '', 0, 0);">$T('cmenu-cat')</a></li>
<li><a class="config" href="$prefix/config/sorting/" onclick="lr('config/sorting/', '', 0, 0);">$T('cmenu-sorting')</a></li>
</ul>
@@ -1152,9 +1154,6 @@ function loadingJSON(){
<li><a class="config" onclick="javascript:timedPause()">$T("smpl-custom")</a></li>
</ul>
<!--#if $varExists('newzbinDetails')#-->
<li><a onclick="getBookmarks()">$T('smpl-getbookmarks')</a></li>
<!--#end if#-->
<!--#if $have_quota#-->
<li><a onclick="resetQuota()">$T('link-resetQuota')</a></li>
<!--#end if#-->
@@ -1183,7 +1182,7 @@ function loadingJSON(){
<div id="RightContainer" class="left-border">
<div id="addNew" class="centerLinks" style="overflow: hidden; display: none;">
<form action="addID" method="get">
<input type="text" style="width:218px;" name="id" value="$T('enterURL')<!--#if $varExists('newzbinDetails') then $T('enterID') else '' #-->" onfocus="clearForm(this, 'Enter URL<!--#if $varExists('newzbinDetails') then " or Report ID" else "" #-->')" onblur="setForm(this, 'Enter URL<!--#if $varExists('newzbinDetails') then " or Report ID" else "" #-->')">
<input type="text" style="width:218px;" name="id" value="$T('enterURL')" onfocus="clearForm(this, 'Enter URL<!--#if $varExists('newzbinDetails') then " or Report ID" else "" #-->')" onblur="setForm(this, 'Enter URL<!--#if $varExists('newzbinDetails') then " or Report ID" else "" #-->')">
<!--#if $cat_list#-->
<select name="cat" >
<optgroup label="$T('category')">

View File

@@ -24,15 +24,15 @@ border-top: 1px dotted #222;
}
#progressBar {
background-color: #fff;
border: 1px solid #000;
background-color: #fff;
border: 1px solid #000;
}
#progressBartop {
background-color: #fff;
border: 1px solid #ccc;
background-color: #fff;
border: 1px solid #ccc;
}
#percentageBar {
background-color: #4B4545;
background-color: #4B4545;
}
@@ -83,7 +83,7 @@ table{border-spacing:0;}
input, select {
input, select, option {
background-color:#232323;
border-color:#3a3a3a;
color:white;
@@ -110,4 +110,4 @@ span.unselected {
color: white;
background-color:#333;
border: 1px solid #555;
}
}

View File

@@ -1,35 +0,0 @@
<!--#include $webdir + "/inc_top.tmpl"#-->
<script type="text/javascript" src="static/javascript/jquery.js"></script>
<script type="text/javascript" src="static/javascript/restart.js"></script>
<br/><br/>
<h4 id="restarting" class="align-center">$T('wizard-restarting')</h4>
<h4 id="complete" class="align-center success hidden">$T('wizard-complete')</h4>
<br />
<br/>
<div id="tips" class="hidden">
$T('wizard-tip1') <span class="bold">$T('wizard-tip2')</span><br/>
<!--#if len($urls) > 1#--><!--#set $s = 's'#--><!--#else#--><!--#set $s = ''#--><!--#end if#-->
<!--#set $tip3 = $T('wizard-tip3') % $s#-->
$tip3:<br/><br/>
<div class="quoteBlock">
<!--#set $i = 0#-->
<!--#for $url in $urls#-->
<!--#set $i = $i+1#-->
<a href="$url">$url</a><!--#if $i != len($urls)#--><br /><!--#end if#-->
<!--#end for#-->
</div><br/>
$T('wizard-tip4')
<br/><br/>
$T('wizard-tip-wiki') <a href="$helpuri">wiki</a>
</div>
</div>
<hr /><br/>
<div class="full-width">
<table class="full-width">
<tr class="align-center">
<td><input type="hidden" name="session" id="apikey" value="$session"><input class="bigbutton disabled" type="button" onclick="document.location ='$access_url'" value="$T('wizard-goto')" disabled="disabled"/></td>
</tr>
</table>
</div>
<!--#include $webdir + "/inc_bottom.tmpl"#-->

View File

@@ -31,7 +31,7 @@ $T('wizard-explain-server')
<div id="connections-tip" class="tips">$T('wizard-server-con-explain') $T('wizard-server-con-eg')</div>
<div id="connections-error" class="error-text hidden">$T('wizard-server-number')</div>
<br class="clear" />
<label><span class="label">$T('srv-ssl')</span>
<label for="srv-ssl"><!--#if $have_ssl then $T('srv-ssl') else '<span class="disabled-text">'+$T('srv-ssl')+'</span> (pyopenssl (python-ssl) '+$T('opt-notInstalled')+')'#-->
<input class="validate-text" class="radio" type="checkbox" name="ssl" value="1" <!--#if $have_ssl then '' else 'disabled'#--><!--#if $ssl == 1 then 'checked' else ''#-->></label>
<div class="tips">$T('wizard-server-ssl-explain')</div>
<br class="clear" />

View File

@@ -1,39 +1,34 @@
<!--#include $webdir + "/inc_top.tmpl"#-->
<form action="./four" method="post" autocomplete="off">
<p>$T('wizard-index-explain')</p>
<div id="serverDetails">
<h3><a href="http://$newzbin_url" target="_blank">Newzbin2.es</a> ($T('wizard-optional'))</h3>
<label class="label">$T('srv-username'):</label><input type="text" size="20" value="$newzbin_user" name="newzbin_user">
<br class="clear" />
<label class="label">$T('srv-password'):</label><input type="password" size="20" value="$newzbin_pass" name="newzbin_pass">
<br class="clear" />
<input type="checkbox" name="newzbin_bookmarks" id="newzbin_bookmarks" value="1" <!--#if $newzbin_bookmarks == 1 then 'checked="checked"' else ''#-->> <label for="newzbin_bookmarks">$T('wizard-index-bookmark')</label><br />
<h3><a href="http://nzbmatrix.com" target="_blank">NZBMatrix.com</a> ($T('wizard-optional'))</h3>
<label class="label">$T('srv-username'):</label><input type="text" size="20" value="$matrix_user" name="matrix_user">
<br class="clear" />
<label class="label">$T('opt-apikey'):</label><input type="text" size="20" value="$matrix_apikey" name="matrix_apikey">
</div></div>
<script type="text/javascript" src="static/javascript/jquery.js"></script>
<script type="text/javascript" src="static/javascript/restart.js"></script>
<br/><br/>
<h4 id="restarting" class="align-center">$T('wizard-restarting')</h4>
<h4 id="complete" class="align-center success hidden">$T('wizard-complete')</h4>
<br />
<br/>
<div id="tips" class="hidden">
$T('wizard-tip1') <span class="bold">$T('wizard-tip2')</span><br/>
<!--#set $tip3 = $T('wizard-tip3') % ''#-->
$tip3<br/><br/>
<div class="quoteBlock">
<!--#set $i = 0#-->
<!--#for $url in $urls#-->
<!--#set $i = $i+1#-->
<a href="$url">$url</a><!--#if $i != len($urls)#--><br /><!--#end if#-->
<!--#end for#-->
</div><br/>
$T('wizard-tip4')
<br/><br/>
$T('wizard-tip-wiki') <a href="$helpuri">wiki</a>
</div>
</div>
<hr /><br/>
<div class="full-width">
<table class="full-width">
<tr>
<td><input class="bigbutton" type="button" onclick="document.location ='./two'" value="&lsaquo; $T('wizard-previous')" /></td>
<td>
<div class="align-center">
<!--#for $step in xrange($steps)#-->
<!--#set $step = $step + 1#-->
<span class="<!--#if $step == $number then 'selected' else 'unselected'#-->">$step</span>
<!--#end for#-->
</div>
</td>
<td class="align-right"><input class="bigbutton" type="submit" value="$T('wizard-next') &raquo;" /></td>
<tr class="align-center">
<td><input type="hidden" name="session" id="apikey" value="$session"><input class="bigbutton disabled" type="button" onclick="document.location ='$access_url'" value="$T('wizard-goto')" disabled="disabled"/></td>
</tr>
</table>
</div>
</form>
<!--#include $webdir + "/inc_bottom.tmpl"#-->
<!--#include $webdir + "/inc_bottom.tmpl"#-->

103
make_dmg.py Normal file
View File

@@ -0,0 +1,103 @@
#!/usr/bin/env python -OO
#
# Copyright 2008-2012 The SABnzbd-Team <team@sabnzbd.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# 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 os
import sys
import re
if len(sys.argv) < 2:
print 'Usage: %s <release>' % os.path.split(sys.argv[0])[1]
exit(1)
# Setup file names
release = sys.argv[1]
prod = 'SABnzbd-' + release
fileDmg = prod + '-osx.dmg'
fileOSr = prod + '-osx-src.tar.gz'
fileImg = prod + '.sparseimage'
builds = ('sl', 'lion', 'ml')
build_folders = (
'OS X 10.5 and 10.6 (Leopards)',
'OS X 10.7 (Lion)',
'OS X 10.8 (Mountain Lion)'
)
# Check presense of all builds
build_paths = []
for build in builds:
path = os.path.join(os.environ['HOME'], 'project/osx/%s-%s.cpio' % (prod, build))
if os.path.exists(path):
build_paths.append(path)
else:
print 'Missing build %s' % path
exit(1)
# Create sparseimage from template
os.system("unzip -o osx/image/template.sparseimage.zip")
os.rename('template.sparseimage', fileImg)
# mount sparseimage and modify volume label
os.system("hdiutil mount %s | grep /Volumes/SABnzbd >mount.log" % fileImg)
# Rename the volume
fp = open('mount.log', 'r')
data = fp.read()
fp.close()
os.remove('mount.log')
m = re.search(r'/dev/(\w+)\s+', data)
volume = 'SABnzbd-' + str(release)
os.system('diskutil rename %s %s' % (m.group(1), volume))
authority = os.environ.get('SIGNING_AUTH')
# Unpack build into image and sign if possible
for build in xrange(len(builds)):
vol_path = '/Volumes/%s/%s/' % (volume, build_folders[build])
os.system('ditto -x -z "%s" "%s"' % (build_paths[build], vol_path))
if authority:
app_name = '%s-%s' % (volume, builds[build])
os.system('codesign -f -i "%s" -s "%s" "%s/SABnzbd.app"' % (app_name, authority, vol_path))
# Put README.rtf in root
from_path = '/Volumes/%s/%s/SABnzbd.app/Contents/Resources/Credits.rtf' % (volume, build_folders[0])
to_path = '/Volumes/%s/README.rtf' % volume
os.system('cp "%s" "%s"' % (from_path, to_path))
# Unmount sparseimage
print 'Eject volume'
os.system("hdiutil eject /Volumes/%s/>/dev/null" % volume)
print 'Wait 1 second'
os.system("sleep 1")
# Convert sparseimage to read-only compressed dmg
print 'Create DMG file'
if os.path.exists(fileDmg):
os.remove(fileDmg)
os.system("hdiutil convert %s -format UDBZ -o %s>/dev/null" % (fileImg, fileDmg))
# Remove sparseimage
os.system("rm %s>/dev/null" % fileImg)
print 'Make image internet-enabled'
os.system("hdiutil internet-enable %s" % fileDmg)
print 'Copy GZ file'
os.system('cp ~/project/osx/%s .' % fileOSr)

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

View File

Binary file not shown.

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

View File

Binary file not shown.

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 902 B

BIN
osx/resources/sab_idle.tiff Normal file
View File

Binary file not shown.

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -34,12 +34,13 @@ except ImportError:
try:
import py2app
from setuptools import setup
OSX_LION = [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 7, 0]
OSX_SL = not OSX_LION and [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 6, 0]
OSX_LEOPARD = not (OSX_LION or OSX_SL)
OSX_ML = [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 8, 0]
OSX_LION = not OSX_ML and [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 7, 0]
OSX_SL = not OSX_LION and not OSX_ML
class WindowsError (): pass
except ImportError:
py2app = None
OSX_ML = OSX_LION = OSX_SL = False
VERSION_FILE = 'sabnzbd/version.py'
VERSION_FILEAPP = 'osx/resources/InfoPlist.strings'
@@ -47,8 +48,8 @@ VERSION_FILEAPP = 'osx/resources/InfoPlist.strings'
my_version = 'unknown'
my_baseline = 'unknown'
def DeleteFiles(name):
''' Delete one file or set of files from wild-card spec '''
def delete_files(name):
""" Delete one file or set of files from wild-card spec """
for f in glob.glob(name):
try:
if os.path.exists(f):
@@ -95,7 +96,7 @@ def PatchVersion(name):
try:
pipe = subprocess.Popen(GitStatus, shell=True, stdout=subprocess.PIPE).stdout
for line in pipe.read().split('\n'):
if 'nothing to commit' in line:
if 'nothing to commit' in line or 'nothing added to commit' in line:
state = ''
break
pipe.close()
@@ -151,8 +152,7 @@ def PairList(src):
lst.append((path, flist))
else:
path, name = os.path.split(item)
items = []
items.append(name)
items = [name]
lst.append((path, items))
return lst
@@ -207,7 +207,7 @@ def Dos2Unix(name):
def Unix2Dos(name):
""" Read file, remove \r, replace \n by \r\n and write back """
base, ext = os.path.splitext(name)
if ext.lower() not in ('.py', '.txt', '.css', '.js', '.tmpl', '.sh', '.cmd'):
if ext.lower() not in ('.py', '.txt', '.css', '.js', '.tmpl', '.sh', '.cmd', '.mkd'):
return
print name
@@ -230,9 +230,9 @@ def Unix2Dos(name):
def rename_file(folder, old, new):
oldpath = "%s/%s" % (folder, old)
newpath = "%s/%s" % (folder, new)
try:
oldpath = "%s/%s" % (folder, old)
newpath = "%s/%s" % (folder, new)
if os.path.exists(newpath):
os.remove(newpath)
os.rename(oldpath, newpath)
@@ -246,6 +246,11 @@ print sys.argv[0]
Git = CheckPath('git')
ZipCmd = CheckPath('zip')
UnZipCmd = CheckPath('unzip')
if os.name != 'nt':
PanDoc = CheckPath('pandoc')
else:
PanDoc = None
if os.name == 'nt':
msg = 'Requires the standard version of NSIS'
NSIS = CheckPath('makensis')
@@ -254,7 +259,7 @@ if os.name == 'nt':
os.system('%s >%s' % (NSIS, log))
if 'Unicode' not in open(log).read():
msg = ''
DeleteFiles(log)
delete_files(log)
if msg:
print msg
exit(1)
@@ -293,11 +298,14 @@ Win32TempName = 'SABnzbd-windows.exe'
fileIns = prod + '-win32-setup.exe'
fileBin = prod + '-win32-bin.zip'
fileSrc = prod + '-src.tar.gz'
fileDmg = prod + '-osx.dmg'
fileDmgLp = prod + '-osx-leopard.dmg'
fileDmg_ml = prod + '-osx-mountainlion.dmg'
fileDmg_lion = prod + '-osx-lion.dmg'
fileDmg_sl = prod + '-osx-snowleopard.dmg'
fileOSr = prod + '-osx-src.tar.gz'
fileImg = prod + '.sparseimage'
if OSX_SL: postfix = 'sl'
if OSX_LION: postfix = 'lion'
if OSX_ML: postfix = 'ml'
PatchVersion(release)
@@ -305,7 +313,7 @@ PatchVersion(release)
# List of data elements, directories end with a '/'
data_files = [
'ABOUT.txt',
'README.txt',
'README.mkd',
'INSTALL.txt',
'GPL2.txt',
'GPL3.txt',
@@ -351,60 +359,30 @@ if target == 'app':
os.system(GitRevertVersion)
exit(1)
if not PanDoc:
print "Sorry, requires pandoc in the $PATH"
os.system(GitRevertVersion)
exit(1)
# Check which Python flavour
apple_py = 'ActiveState' not in sys.copyright
#Create sparseimage from template
os.system("unzip osx/image/template.sparseimage.zip")
os.rename('sabnzbd-template.sparseimage', fileImg)
#mount sparseimage and modify volume label
os.system("hdiutil mount %s | grep /Volumes/SABnzbd >mount.log" % (fileImg))
# Select OSX version specific background image
# Take care to preserve the special attributes of the background image file
if OSX_LION:
# Lion and higher: generates SnowLeopard/Lion DMG
f = open('osx/image/sabnzbd.png', 'rb')
png = f.read()
f.close()
else:
# Snow Leopard and lower: generates Leopard DMG
fileDmg = fileDmgLp
f = open('osx/image/sabnzbd_leopard.png', 'rb')
png = f.read()
f.close()
f = open('/Volumes/SABnzbd/sabnzbd.png', 'wb')
f.write(png)
f.close()
# Rename the volume
fp = open('mount.log', 'r')
data = fp.read()
fp.close()
os.remove('mount.log')
m = re.search(r'/dev/(\w+)\s+', data)
volume = 'SABnzbd-' + str(my_version)
os.system('disktool -n %s %s' % (m.group(1), volume))
options['description'] = 'SABnzbd ' + str(my_version)
#Create MO files
os.system('python ./tools/make_mo.py all')
# Remove previous build result
os.system('rm -rf dist/ build/')
#build SABnzbd.py
# Create MO files
os.system('python ./tools/make_mo.py')
# build SABnzbd.py
sys.argv[1] = 'py2app'
# Due to ApplePython bug
if apple_py:
sys.argv.append('-p')
sys.argv.append('email')
APP = ['SABnzbd.py']
DATA_FILES = ['interfaces', 'locale', 'email', ('', glob.glob("osx/resources/*"))]
NZBFILE = dict(
CFBundleTypeExtensions = [ "nzb","zip","rar" ],
CFBundleTypeExtensions = [ "nzb" ],
CFBundleTypeIconFile = 'nzbfile.icns',
CFBundleTypeMIMETypes = [ "text/nzb" ],
CFBundleTypeName = 'NZB File',
@@ -412,13 +390,19 @@ if target == 'app':
LSTypeIsPackage = 0,
NSPersistentStoreTypeKey = 'Binary',
)
OPTIONS = {'argv_emulation': not apple_py, 'iconfile': 'osx/resources/sabnzbdplus.icns', 'plist': {
'NSUIElement':1,
'CFBundleShortVersionString':release,
'NSHumanReadableCopyright':'The SABnzbd-Team',
'CFBundleIdentifier':'org.sabnzbd.team',
'CFBundleDocumentTypes':[NZBFILE]
}}
OPTIONS = {'argv_emulation': not apple_py,
'iconfile': 'osx/resources/sabnzbdplus.icns',
'plist': {
'NSUIElement':1,
'CFBundleShortVersionString':release,
'NSHumanReadableCopyright':'The SABnzbd-Team',
'CFBundleIdentifier':'org.sabnzbd.team',
'CFBundleDocumentTypes':[NZBFILE],
},
'packages': "email,xml,Cheetah",
'excludes': ["pywin", "pywin.debugger", "pywin.debugger.dbgcon", "pywin.dialogs",
"pywin.dialogs.list", "Tkconstants", "Tkinter", "tcl"]
}
setup(
app=APP,
@@ -427,64 +411,69 @@ if target == 'app':
setup_requires=['py2app'],
)
#copy unrar & par2 binary to avoid striping
# Remove 64bit code
if not OSX_SL:
os.system("mv dist/SABnzbd.app dist/SABnzbd.app.temp")
os.system("ditto --arch i386 --arch ppc dist/SABnzbd.app.temp dist/SABnzbd.app/")
os.system("rm -rf dist/SABnzbd.app.temp")
# copy unrar & par2 binary
os.system("mkdir dist/SABnzbd.app/Contents/Resources/osx>/dev/null")
os.system("mkdir dist/SABnzbd.app/Contents/Resources/osx/par2>/dev/null")
os.system("cp -pR osx/par2/ dist/SABnzbd.app/Contents/Resources/osx/par2>/dev/null")
os.system("mkdir dist/SABnzbd.app/Contents/Resources/osx/unrar>/dev/null")
os.system("cp -pR osx/unrar/license.txt dist/SABnzbd.app/Contents/Resources/osx/unrar/ >/dev/null")
if OSX_LION:
os.system("cp -pR osx/unrar/unrar dist/SABnzbd.app/Contents/Resources/osx/unrar/ >/dev/null")
else:
if OSX_SL:
os.system("cp -pR osx/unrar/unrar-leopard dist/SABnzbd.app/Contents/Resources/osx/unrar/unrar >/dev/null")
else:
os.system("cp -pR osx/unrar/unrar dist/SABnzbd.app/Contents/Resources/osx/unrar/ >/dev/null")
os.system("cp icons/sabnzbd.ico dist/SABnzbd.app/Contents/Resources >/dev/null")
os.system("cp README.rtf dist/SABnzbd.app/Contents/Resources/Credits.rtf >/dev/null")
os.system("pandoc -f markdown -t rtf -s -o dist/SABnzbd.app/Contents/Resources/Credits.rtf README.mkd >/dev/null")
os.system("find dist/SABnzbd.app -name .git | xargs rm -rf")
# Sign the App if possible
authority = os.environ.get('SIGNING_AUTH')
if authority:
os.system('codesign -f -i "%s" -s "%s" dist/SABnzbd.app' % (volume, authority))
# Remove source files to prevent re-compilation, which would invalidate signing
py_ver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
os.system("find dist/SABnzbd.app/Contents/Resources/lib/python%s/Cheetah -name '*.py' | xargs rm" % py_ver)
os.system("find dist/SABnzbd.app/Contents/Resources/lib/python%s/xml -name '*.py' | xargs rm" % py_ver)
os.system('rm dist/SABnzbd.app/Contents/Resources/site.py')
# Add the SabNotifier app
if OSX_ML and os.path.exists('/project/sabnotifier/SABnzbd.app'):
os.system("cp -pR /project/sabnotifier/SABnzbd.app dist/SABnzbd.app/Contents/Resources/")
#copy app to mounted sparseimage
os.system("cp -r dist/SABnzbd.app /Volumes/%s/>/dev/null" % volume)
print 'Create src %s' % fileOSr
os.system('tar -czf %s --exclude ".git*" --exclude "sab*.zip" --exclude "SAB*.tar.gz" --exclude "*.cmd" --exclude "*.pyc" '
'--exclude "*.sparseimage" --exclude "dist" --exclude "build" --exclude "*.nsi" --exclude "win" --exclude "*.dmg" '
'./ >/dev/null' % (fileOSr) )
# Copy README.txt
os.system("cp README.rtf /Volumes/%s/" % volume)
# Remove site.py to prevent re-compilation (otherwise the OSX Firewall may complain)
os.remove('/Volumes/%s/SABnzbd.app/Contents/Resources/site.py' % volume)
#Unmount sparseimage
os.system("hdiutil eject /Volumes/%s/>/dev/null" % volume)
# Add License files
os.mkdir("dist/SABnzbd.app/Contents/Resources/licenses/")
os.system("cp -p licenses/*.txt dist/SABnzbd.app/Contents/Resources/licenses/")
os.system("cp -p *.txt dist/SABnzbd.app/Contents/Resources/licenses/")
os.system("sleep 5")
#Convert sparseimage to read only compressed dmg
if os.path.exists(fileDmg):
os.remove(fileDmg)
os.system("hdiutil convert %s -format UDBZ -o %s>/dev/null" % (fileImg, fileDmg))
#Remove sparseimage
os.system("rm %s>/dev/null" % (fileImg))
#Make image internet-enabled
os.system("hdiutil internet-enable %s" % fileDmg)
# Archive result to share
dest_path = '/Volumes/VMware Shared Folders/osx'
if not os.path.exists(dest_path):
dest_path = '$HOME/project/osx'
cpio_path = os.path.join(dest_path, prod) + '-' + postfix + '.cpio'
print 'Create CPIO file %s' % cpio_path
delete_files(cpio_path)
os.system('ditto -c -z dist/ "%s"' % cpio_path)
if OSX_ML:
print 'Create src %s' % fileOSr
delete_files(fileOSr)
os.system('tar -czf %s --exclude ".git*" --exclude "sab*.zip" --exclude "SAB*.tar.gz" --exclude "*.cmd" --exclude "*.pyc" '
'--exclude "*.sparseimage*" --exclude "dist" --exclude "build" --exclude "*.nsi" --exclude "win" --exclude "*.dmg" '
'./ >/dev/null' % os.path.join(dest_path, fileOSr) )
os.system(GitRevertApp + VERSION_FILEAPP)
os.system(GitRevertApp + VERSION_FILE)
elif target in ('binary', 'installer'):
if not py2exe:
print "Sorry, only works on Windows!"
os.system(GitRevertVersion)
exit(1)
#run_times = check_runtimes()
# Create MO files
os.system('tools\\make_mo.py all')
@@ -518,12 +507,12 @@ elif target in ('binary', 'installer'):
for tup in options['data_files']:
for file in tup[1]:
name, ext = os.path.splitext(file)
if ext.lower() in ('.txt', '.cmd'):
if ext.lower() in ('.txt', '.cmd', '.mkd'):
Unix2Dos("dist/%s" % file)
DeleteFiles('dist/Sample-PostProc.sh')
DeleteFiles('dist/PKG-INFO')
delete_files('dist/Sample-PostProc.sh')
delete_files('dist/PKG-INFO')
DeleteFiles('*.ini')
delete_files('*.ini')
############################
# Generate the windowed-app
@@ -560,37 +549,40 @@ elif target in ('binary', 'installer'):
############################
# Remove unwanted system DLL files that Py2Exe copies when running on Win7
DeleteFiles(r'dist\lib\API-MS-Win-*.dll')
DeleteFiles(r'dist\lib\MSWSOCK.DLL')
DeleteFiles(r'dist\lib\POWRPROF.DLL')
delete_files(r'dist\lib\API-MS-Win-*.dll')
delete_files(r'dist\lib\MSWSOCK.DLL')
delete_files(r'dist\lib\POWRPROF.DLL')
delete_files(r'dist\lib\KERNELBASE.dll')
############################
# Remove .git residue
DeleteFiles(r'dist\interfaces\Config\.git')
delete_files(r'dist\interfaces\Config\.git')
############################
# Copy MS runtime files or Curl
if sys.version_info > (2, 5):
#Won't work with OpenSSL DLLs :(
#shutil.copy2(os.path.join(run_times, r'Microsoft.VC90.CRT.manifest'), r'dist')
#shutil.copy2(os.path.join(run_times, r'msvcp90.dll'), r'dist')
#shutil.copy2(os.path.join(run_times, r'msvcr90.dll'), r'dist')
#shutil.copy2(os.path.join(run_times, r'lib\Microsoft.VC90.CRT.manifest'), r'dist\lib')
pass
else:
# Copy Curl if needed
if sys.version_info < (2, 6):
# Curl for Python 2.5
os.system(r'unzip -o win\curl\curl.zip -d dist\lib')
############################
# Fix icon issue with NZB association
os.system(r'copy dist\icons\nzb.ico dist')
############################
# Rename MKD file
rename_file('dist', 'README.mkd', 'README.txt')
############################
if target == 'installer':
delete_files(fileIns)
os.system('makensis.exe /v3 /DSAB_PRODUCT=%s /DSAB_VERSION=%s /DSAB_FILE=%s NSIS_Installer.nsi.tmp' % \
(prod, release, fileIns))
DeleteFiles('NSIS_Installer.nsi.tmp')
delete_files('NSIS_Installer.nsi.tmp')
if not os.path.exists(fileIns):
print 'Fatal error creating %s' % fileIns
exit(1)
DeleteFiles(fileBin)
#write_dll_message('dist/IMPORTANT_MESSAGE.txt')
delete_files(fileBin)
os.rename('dist', prod)
os.system('zip -9 -r -X %s %s' % (fileBin, prod))
time.sleep(1.0)
@@ -657,6 +649,10 @@ else:
shutil.copy2(file, dest)
Dos2Unix(fullname)
############################
# Rename MKD file
rename_file(root, 'README.mkd', 'README.txt')
os.chdir(root)
os.chdir('..')
@@ -664,4 +660,3 @@ else:
CreateTar('srcdist', fileSrc, prod)
os.system(GitRevertVersion)

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-03-09 19:01+0000\n"
"PO-Revision-Date: 2012-03-14 04:51+0000\n"
"Last-Translator: Rene <Unknown>\n"
"POT-Creation-Date: 2012-04-28 12:01+0000\n"
"PO-Revision-Date: 2012-08-03 17:24+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: Danish <da@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-03-15 05:11+0000\n"
"X-Generator: Launchpad (build 14933)\n"
"X-Launchpad-Export-Date: 2012-08-04 05:38+0000\n"
"X-Generator: Launchpad (build 15742)\n"
#: email/email.tmpl:1
msgid ""
@@ -65,42 +65,42 @@ msgid ""
"<!--#end if#-->\n"
msgstr ""
"##\n"
"## Default Email template for SABnzbd\n"
"## This a Cheetah template\n"
"## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
"## Standard Email skabelon til SABnzbd\n"
"## Dette er en Cheetah skabelon\n"
"## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Newlines and whitespace are significant!\n"
"## Linjeskift og blanktegn er betydelig!\n"
"##\n"
"## These are the email headers\n"
"## Disse er e-mail-headerne \n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd has <!--#if $status then \"completed\" else \"failed\" #--> "
"Subject: SABnzbd har <!--#if $status then \"hentet\" else \"fejlet\" #--> "
"job $name\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
"## Efter dette kommer body, den tomme linje kræves!\n"
"\n"
"Hej,\n"
"<!--#if $status #-->\n"
"SABnzbd har downloaded \"$name\" <!--#if $msgid==\"\" then \"\" else "
"\"(newzbin #\" + $msgid + \")\"#-->\n"
"SABnzbd har hentet \"$name\" <!--#if $msgid==\"\" then \"\" else \"(newzbin "
"#\" + $msgid + \")\"#-->\n"
"<!--#else#-->\n"
"SABnzbd har ikke downloaded \"$name\" <!--#if $msgid==\"\" then \"\" else "
"SABnzbd kunne ikke hente \"$name\" <!--#if $msgid==\"\" then \"\" else "
"\"(newzbin #\" + $msgid + \")\"#-->\n"
"<!--#end if#-->\n"
"Færdig kl. $end_time\n"
"Downloaded $size\n"
"Hentet $size\n"
"\n"
"Resultat af job:\n"
"<!--#for $stage in $stages #-->\n"
"Stage $stage <!--#slurp#-->\n"
"Etape $stage <!--#slurp#-->\n"
"<!--#for $result in $stages[$stage]#-->\n"
" $result <!--#slurp#-->\n"
"<!--#end for#-->\n"
"<!--#end for#-->\n"
"<!--#if $script!=\"\" #-->\n"
"Output from user script \"$script\" (Exit code = $script_ret):\n"
"Output fra bruger script \"$script\" (Exit code = $script_ret):\n"
"$script_output\n"
"<!--#end if#-->\n"
"<!--#if $status #-->\n"
@@ -138,20 +138,20 @@ msgid ""
"Bye\n"
msgstr ""
"##\n"
"## RSS Email template for SABnzbd\n"
"## This a Cheetah template\n"
"## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
"## RSS Email skabelon til SABnzbd\n"
"## Dette er Cheetah skabelon\n"
"## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Newlines and whitespace are significant!\n"
"## Linjeskift og blanktegn er betydelig!\n"
"##\n"
"## These are the email headers\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"
"## After this comes the body, the empty line is required!\n"
"## Efter dette kommer body, den tomme linje kræves!\n"
"\n"
"Hej,\n"
"\n"
@@ -189,24 +189,24 @@ msgid ""
"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"
"## 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"
"## Newlines and whitespace are significant!\n"
"## Linjeskift og blanktegn er betydelig!\n"
"##\n"
"## These are the email headers\n"
"## Dette er email headers\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd failed to fetch an NZB\n"
"Subject: SABnzbd kunne ikke hente en NZB\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
"## Efter dette kommer body, den tomme linje kræves!\n"
"\n"
"Hi,\n"
"Hej,\n"
"\n"
"SABnzbd has failed to retrieve the NZB from $url.\n"
"The error message was: $msg\n"
"SABnzbd kunne ikke hente NZB fra $url.\n"
"Fejl meddelelsen er: $msg\n"
"\n"
"Bye\n"
"Farvel\n"

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-03-09 19:01+0000\n"
"PO-Revision-Date: 2011-06-26 10:50+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-04-28 12:01+0000\n"
"PO-Revision-Date: 2012-12-28 10:58+0000\n"
"Last-Translator: Thomas Lucke (Lucky) <Unknown>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-03-11 05:02+0000\n"
"X-Generator: Launchpad (build 14914)\n"
"X-Launchpad-Export-Date: 2012-12-29 05:11+0000\n"
"X-Generator: Launchpad (build 16378)\n"
#: email/email.tmpl:1
msgid ""
@@ -189,3 +189,24 @@ msgid ""
"\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"

Some files were not shown because too many files have changed in this diff Show More