Compare commits

..

156 Commits

Author SHA1 Message Date
unknown
9a3a7fa4af Version increment 2015-07-26 15:47:34 -06:00
unknown
3fb8be044d Route fixes 2015-07-26 15:45:35 -06:00
unknown
cdff1d2d40 Distribution fix 2015-07-26 15:20:08 -06:00
unknown
dc56a77047 Created github distribution app 2015-07-26 15:14:29 -06:00
Kayomani
0a9f19b256 Add anime cap to ipt and remove New tag from PTM 2015-07-26 19:01:08 +01:00
Kayomani
3add87e072 Add missing IPT anime category 2015-07-26 18:05:16 +01:00
Kayomani
dba21c5c3e Change file to lower case and fix console issue 2015-07-26 17:27:04 +01:00
Kayomani
bd8819dd72 Change bakabt to lower case as in convention and fix duplicate command line option 2015-07-26 17:15:37 +01:00
unknown
e5a407998d Revert bakabt casing change 2015-07-26 10:05:34 -06:00
unknown
4cb25b9e4b Merge branch 'master' of https://github.com/zone117x/Jackett into develop 2015-07-26 10:04:17 -06:00
unknown
2c8fa00791 Fixed logo image requests using Name rather than ID 2015-07-26 10:02:27 -06:00
Kayomani
652fa35fa7 Merge pull request #113 from sdesbure/master
Use correct name for bakabt.png
2015-07-26 16:33:32 +01:00
Sylvain Desbureaux
014b3f8b6a use correct name for bakabt.png
older one was not using the correct case, which causes an error on unix (BakaBT.png is the correct not bakabt.png)
2015-07-26 17:07:00 +02:00
Kayomani
3b87369458 New: Viewable release cache 2015-07-26 15:22:20 +01:00
Kayomani
8c2141b04f Fix wrong description for PTM 2015-07-26 11:57:29 +01:00
Kayomani
9f840475a1 Fix PTM not parsing dates 2015-07-26 11:53:38 +01:00
Kayomani
e5a54df60c Tweak read me 2015-07-26 11:39:27 +01:00
Kayomani
36f894e3f4 Merge changes 2015-07-26 11:36:57 +01:00
Kayomani
1f6046bbe0 Fix IPT 2015-07-26 11:27:50 +01:00
unknown
01dc9cb0a5 Replaced most indexers' byte size string parsing with shared helper function 2015-07-25 21:53:53 -06:00
unknown
abdca8cee8 Implemented HD-Space 2015-07-25 21:48:18 -06:00
unknown
fd9c79e289 Implemented pretome 2015-07-25 20:33:01 -06:00
Kayomani
676a1824db Merge BakaBT Fix 2015-07-26 01:22:26 +01:00
Kayomani
289d011991 BakaBT fix minium ratio not set 2015-07-26 01:17:19 +01:00
Kayomani
c9072b5d67 Merge pull request #108 from zone117x/develop
BakaBT + Switch from x64 back to any cpu
2015-07-26 01:08:16 +01:00
Kayomani
5713841499 Baka BT Remove Season from search query 2015-07-26 01:04:16 +01:00
Kayomani
7ef1f1e460 Fix logo not copying 2015-07-26 00:53:45 +01:00
Kayomani
ad50101d82 Implement BakaBT, change Console to not build as x64, Add test framework 2015-07-26 00:51:55 +01:00
Matthew Little
4faaec0090 Update README.md 2015-07-25 10:29:28 -06:00
Matthew Little
c35d3328d5 Update README.md 2015-07-25 10:28:34 -06:00
Kayomani
f56587fb24 Merge pull request #106 from zone117x/develop
Fix SCC not saving and AlphaRatio
2015-07-25 11:49:11 +01:00
Kayomani
e47cf66093 Fix SCC not saving and AlphaRatio 2015-07-25 11:47:01 +01:00
Kayomani
073ddbe272 Resolve Merge conflict 2015-07-25 10:26:01 +01:00
Kayomani
a31098fbe7 Fix SCC and duplicate console option 2015-07-25 10:24:15 +01:00
Kayomani
af9b4e99e2 Merge fixes from develop 2015-07-25 09:35:25 +01:00
Kayomani
59a62daa34 Make lib curl more stable 2015-07-25 09:34:15 +01:00
unknown
2c1ff1a881 Fix for SceneTime timezone on mono 2015-07-24 19:25:30 -06:00
unknown
9fceea9aa8 Fixed extra slashes in URLs 2015-07-24 18:41:24 -06:00
unknown
c3fe26f4b5 Fix for SceneTime 2015-07-24 18:27:35 -06:00
unknown
63b0ca6b72 FreshonTV fix 2015-07-24 18:23:31 -06:00
Kayomani
58f43b8b44 Merge pull request #105 from zone117x/develop
Merge fixes from testing
2015-07-24 22:54:44 +01:00
Kayomani
92a573d804 Various bugfixes. 2015-07-24 22:38:31 +01:00
Kayomani
44800491c0 Added UI for allowing external access, stop server listening on the old port when changing ports. Config migration bug fixes. 2015-07-24 20:15:08 +01:00
Kayomani
64acf70b77 Merge pull request #104 from zone117x/develop
Command line args.  Supercede pull #102 from sdesbure:master
2015-07-24 00:09:32 +01:00
Kayomani
800e764f60 Command line args. Superceade pull #102 from sdesbure:master 2015-07-24 00:07:36 +01:00
Kayomani
469c44b923 Merge branch 'master' of https://github.com/zone117x/Jackett.git 2015-07-23 22:15:41 +01:00
Kayomani
90118b402a Merge branch 'develop' 2015-07-23 22:14:55 +01:00
Kayomani
5366cb42b7 Fix unreliable torrentleech date parsing 2015-07-23 22:14:36 +01:00
Kayomani
541320033e Merge pull request #103 from zone117x/develop
Passwords inputs are now the correct type. Fix configure_indexer not returning errors. Fix build warning. Change AB, HDT, MTTV, PHD, ST to use generic web client.
2015-07-23 21:37:42 +01:00
Kayomani
f8eb72414d Passwords inputs are now the correct type. Fix configure_indexer not returning errors. Fix build warning. Change AB, HDT, MTTV, PHD, ST to use generic web client. 2015-07-23 21:36:23 +01:00
Matthew Little
9579719376 Merge pull request #101 from zone117x/develop
Develop
2015-07-22 23:20:21 -06:00
Matthew Little
cef4a5c94d Update README.md 2015-07-22 23:18:41 -06:00
unknown
8a7ab0c5f1 Implemented PrivateHD 2015-07-22 23:16:35 -06:00
unknown
15ee194035 Abstracted common "time ago" date string parsing logic 2015-07-22 23:16:13 -06:00
unknown
bb32831e9f Fixed bug with download proxy url using indexerName instead of indexerID 2015-07-22 21:21:29 -06:00
Matthew Little
c93830325e Update README.md 2015-07-22 18:25:08 -06:00
Kayomani
dced67726b Merge remote-tracking branch 'refs/remotes/origin/develop' 2015-07-23 00:10:27 +01:00
Kayomani
5b87e2f694 Revert "Revert "Refactored to use the RageID lookup disabled, removed Sonarr API setup""
This reverts commit b3ecee2cc9.
2015-07-23 00:09:55 +01:00
Kayomani
9a15f8a965 Couple of bugfixes 2015-07-22 23:48:02 +01:00
Kayomani
d016c6f8ad Fix trackers with non alphanumerics in the name not resolving 2015-07-22 23:06:46 +01:00
Kayomani
8824aa62e5 0.5 Rc1 - Reimplement port change+tray, fix IPT+SSC. Installer fixes. 2015-07-22 23:00:52 +01:00
Kayomani
b85ff8503c Add missed file 2015-07-20 22:30:08 +01:00
Kayomani
3e8688eea8 Merge pull request #99 from zone117x/feature/ServiceRefactor
Merge Feature/service refactor
2015-07-20 22:26:42 +01:00
Kayomani
abfe32661a Merge changes 2015-07-20 22:18:02 +01:00
Kayomani
a908b2b691 Web auth 2015-07-20 22:08:05 +01:00
unknown
d02a19b94b Fix loopback & localhost entry points for mono 2015-07-19 18:26:07 -06:00
unknown
a37f1df313 Fix loopback address not working 2015-07-19 18:06:21 -06:00
unknown
2fa280deae readme change 2015-07-19 17:27:03 -06:00
unknown
a1a45fefb7 Add bB to readme 2015-07-19 17:26:45 -06:00
unknown
8cef953284 Fixed bB cookie persistence 2015-07-19 17:22:08 -06:00
unknown
54a3271d73 Fixed AnimeBytes torznab category 2015-07-19 17:20:16 -06:00
unknown
68d6fef4f2 Merge branch 'feature/ServiceRefactor' of https://github.com/zone117x/Jackett into feature/ServiceRefactor 2015-07-19 17:05:40 -06:00
unknown
5fb7e3a2ae Implemented torznab capabilities feature 2015-07-19 17:05:30 -06:00
Kayomani
52fd3e67a4 Fix issue #65 - Parsing issues due to culuture differences. 2015-07-19 22:57:15 +01:00
Kayomani
507e0d5496 Add logging 2015-07-19 22:31:36 +01:00
Kayomani
fb8db7db57 Merge branch 'feature/ServiceRefactor' of https://github.com/zone117x/Jackett.git 2015-07-19 21:22:25 +01:00
Kayomani
37ae1d6226 Add missing route 2015-07-19 21:22:23 +01:00
unknown
63b48a2af5 Implemented bB tracker 2015-07-19 14:21:31 -06:00
unknown
ffa868e466 Fix for Strike date change 2015-07-19 14:21:14 -06:00
Kayomani
396e4b2d50 Fix merge conflict 2015-07-19 21:16:31 +01:00
Kayomani
03bb51b1ef Add missing files 2015-07-19 21:15:23 +01:00
unknown
977875f622 Fixed indexer register by name 2015-07-19 13:38:41 -06:00
unknown
32c3323de7 Indexer ID rather than class name 2015-07-19 13:28:08 -06:00
unknown
4a993efd6a Fixed TestIndexer async Task 2015-07-19 12:25:47 -06:00
unknown
0001bfbf78 Merge branch 'feature/ServiceRefactor' of https://github.com/zone117x/Jackett into feature/ServiceRefactor 2015-07-19 11:37:18 -06:00
unknown
c2add69276 Fix indexer class lookup by string when name has non-alphanumeric chars 2015-07-19 11:37:08 -06:00
Kayomani
9a93b62247 Tidy up 2015-07-19 18:31:25 +01:00
Kayomani
644cf939ca Bug fix 2015-07-19 18:23:29 +01:00
Kayomani
0dcebe9ced Change indexers to use new api 2015-07-19 18:18:54 +01:00
unknown
b3ecee2cc9 Revert "Refactored to use the RageID lookup disabled, removed Sonarr API setup"
This reverts commit b279c871b1.
2015-07-19 10:59:07 -06:00
unknown
ce4e437733 Added change port argument to console app 2015-07-19 10:57:33 -06:00
unknown
f6d3150784 Added build.bat & installer.iss as solution items 2015-07-19 10:57:05 -06:00
unknown
e9aa7834f2 Minor settings migration bug fix 2015-07-19 10:35:56 -06:00
unknown
89b672f296 Readded SpeedCD to solution 2015-07-19 10:35:34 -06:00
Kayomani
43f5f5eda2 Merge pull request #95 from Kayomani/feature/Refactor2
Feature/refactor2
2015-07-19 15:41:48 +01:00
Kayomani
795688c218 Reinstate changes from merge 2015-07-19 15:22:26 +01:00
Kayomani
3bb22020a6 Fix csproj 2015-07-19 15:03:39 +01:00
Kayomani
32ef46501c Undo Organizational improvements and build warnings fixed 2015-07-19 14:56:48 +01:00
Kayomani
aa23903434 Tray 2015-07-19 14:33:27 +01:00
Kayomani
e50e937a69 Refactor done 2015-07-19 14:22:50 +01:00
unknown
ce7c5fdd48 Implemented speed.cd 2015-07-18 20:19:09 -06:00
unknown
d476174233 Organizational improvements and build warnings fixed 2015-07-18 19:03:24 -06:00
unknown
65aa3211aa Fixed blocking query in ShowRSS 2015-07-18 19:02:47 -06:00
unknown
919d1b4783 Fix showing console error when settings directory cannot be created 2015-07-18 19:02:29 -06:00
unknown
4f5f0402a4 Strike bug fix 2015-07-18 19:00:38 -06:00
Kayomani
e6c2138b32 Interim commit 2015-07-19 01:59:30 +01:00
Kayomani
b366374cf2 Refactor 2015-07-19 01:27:41 +01:00
unknown
b279c871b1 Refactored to use the RageID lookup disabled, removed Sonarr API setup 2015-07-18 14:35:02 -06:00
Matthew Little
7cfa590b94 Merge pull request #88 from Kayomani/hotfix/Bugfixes
HDTorrents bugfix, change AnimeBytes to work with RageId queries and reduce sizes of cards to improve presentation with the large number of indexers
2015-07-18 11:03:01 -06:00
Kayomani
5874a744d7 HDTorrents bugfix and reduce sizes of cards to improve presentation with the large number of indexers 2015-07-18 10:59:18 +01:00
Matthew Little
debc2a45b7 Merge pull request #85 from sdesbure/master
Add of FrenchTorrentDb site
2015-07-16 18:10:58 -06:00
Matthew Little
b90c3d6f83 Merge pull request #81 from damwthomas/ChangingPort
Change port
2015-07-16 18:08:12 -06:00
Sylvain Desbureaux
7ecc89f30f done the Download method for FrenchTorrentDb 2015-07-17 00:24:38 +02:00
Sylvain Desbureaux
dc63db44fc reverting src/Jackett/packages.config 2015-07-17 00:20:14 +02:00
Sylvain Desbureaux
4c89da4bc7 only needed changes in src/Jackett/Jackett.csproj 2015-07-17 00:19:41 +02:00
Sylvain Desbureaux
52b7e53952 No need of Noesis.Javascript 2015-07-16 02:03:19 +02:00
Sylvain Desbureaux
ff6c3a82fa added FrenchTorrentDb in the list of supported sites 2015-07-16 02:01:39 +02:00
Sylvain Desbureaux
1be41c4aff Added FrenchTorrentDb site 2015-07-16 01:59:38 +02:00
ThomasAmpen
46f15f314a Change port 2015-07-14 21:07:55 +02:00
unknown
47a5a7edd5 Readme update 2015-07-13 01:18:10 -06:00
unknown
f91c92326c T411 auto re-fetch token after 48 hours 2015-07-13 01:17:21 -06:00
unknown
2eebea0683 Implemented T411 2015-07-13 01:13:16 -06:00
unknown
cf7d4cb518 App version increment 2015-07-12 23:57:56 -06:00
unknown
ddd86d2279 Improvement for TPB - combined TV and HDTV search into one 2015-07-12 23:57:14 -06:00
unknown
4996bd57e1 Don't use https for HD-Torrents (doesn't work on mono) 2015-07-12 23:39:41 -06:00
unknown
3fd4b08da2 App version increment 2015-07-12 20:03:04 -06:00
unknown
1a7f3c2e3e Readme update 2015-07-12 20:01:36 -06:00
unknown
f4ad01dda7 Implemented BeyondHD 2015-07-12 20:01:02 -06:00
unknown
f2f50e21fa Moved AnimeBytes helper class into its main class file 2015-07-12 20:00:47 -06:00
unknown
5f011d3222 Implemented SceneTime 2015-07-12 15:43:00 -06:00
unknown
757c3ee87a Minor improvements, bug fixes 2015-07-12 13:50:24 -06:00
Matthew Little
c21c83a13e Merge pull request #79 from damwthomas/master
HDTorrents
2015-07-12 13:18:01 -06:00
ThomasAmpen
9595dad645 Forgotten parse 2015-07-12 19:58:46 +02:00
ThomasAmpen
dd658b2e77 DeletedExtentionmethod 2015-07-12 19:54:37 +02:00
ThomasAmpen
389926d86b BrowserUtil, tryparse added 2015-07-12 19:52:32 +02:00
ThomasAmpen
5744e6ff08 Merge branch 'zone117x/master' 2015-07-12 18:54:45 +02:00
ThomasAmpen
ba89d25563 pull from master 2015-07-12 18:23:40 +02:00
damwthomas
6e575a70e3 Merge pull request #2 from damwthomas/HDTorrents
Hdtorrents
2015-07-12 17:49:36 +02:00
ThomasAmpen
bd8463387b HDTorrents 2015-07-12 17:48:37 +02:00
Matthew Little
3b22973b6d Update README.md 2015-07-11 14:34:13 -06:00
unknown
3a6899343a Incremented to app version 0.4.0 2015-07-11 14:30:16 -06:00
unknown
56bbee2f1f Strip most non alphanumeric characters from show titles before searching 2015-07-11 14:23:43 -06:00
unknown
b58566c782 Timezone publish date fixes for Bit-HDTV, BitMeTv, and MoreThanTV 2015-07-11 14:06:13 -06:00
ThomasAmpen
79ee4b4da0 HdTorrents 2015-07-11 21:27:57 +02:00
unknown
dd31c249fd TorrentShack fix for an unlikely bug 2015-07-11 13:26:57 -06:00
unknown
c6357bf30f Fixes for loading saved cookie problems 2015-07-11 12:54:15 -06:00
unknown
e0e3c12d5e Fixed torrent file download for GetStrike 2015-07-11 11:09:52 -06:00
unknown
8e0b138086 Fix for custom PirateBay url 2015-07-11 11:00:44 -06:00
unknown
a6213c1b9a Display app version in web interface 2015-07-11 10:53:18 -06:00
unknown
9ffa461ae3 Fixed autostart feature 2015-07-11 10:42:00 -06:00
unknown
257fbc07b2 Changed app settings location to longer require root on unix 2015-07-11 10:29:20 -06:00
unknown
8d08279895 Bug fixes for number parsing, fixed ThePirateBay indexer 2015-07-11 10:24:41 -06:00
ThomasAmpen
ecdd1f655b Pull from master 2015-07-09 22:24:20 +02:00
Matthew Little
edb629adb4 Update README.md 2015-07-09 14:08:13 -06:00
Matthew Little
43b0403ab4 Merge pull request #78 from Kayomani/master
Add AnimeBytes Tracker
2015-07-09 13:50:25 -06:00
Kayomani
7cf55f41d6 Add AnimeBytes Tracker 2015-07-09 18:44:19 +01:00
946 changed files with 52588 additions and 127984 deletions

View File

@@ -1,295 +0,0 @@
root=true
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
# With more recent updates Visual Studio 2017 supports EditorConfig files out of the box
# Visual Studio Code needs an extension: https://github.com/editorconfig/editorconfig-vscode
# For emacs, vim, np++ and other editors, see here: https://github.com/editorconfig
###############################
# Core EditorConfig Options #
###############################
# All files
[*]
indent_style=space
insert_final_newline=true
charset=utf-8
end_of_line=lf
trim_trailing_whitespace=true
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers=true
csharp_space_after_cast=false
csharp_style_var_elsewhere=true:suggestion
csharp_style_var_for_built_in_types=true:suggestion
csharp_style_var_when_type_is_apparent=true:suggestion
dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none
dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none
# ReSharper properties
resharper_align_linq_query=true
resharper_align_multiline_argument=true
resharper_align_multiline_calls_chain=true
resharper_align_multiline_extends_list=true
resharper_align_multiline_for_stmt=true
resharper_align_tuple_components=true
resharper_csharp_alignment_tab_fill_style=optimal_fill
resharper_csharp_align_multiline_parameter=true
resharper_csharp_align_multiple_declaration=true
resharper_csharp_indent_pars=outside
resharper_csharp_keep_blank_lines_in_code=0
resharper_csharp_keep_blank_lines_in_declarations=1
resharper_csharp_max_line_length=125
resharper_csharp_stick_comment=false
resharper_csharp_wrap_after_invocation_lpar=true
resharper_force_attribute_style=join
resharper_indent_invocation_pars=outside
resharper_indent_method_decl_pars=outside
resharper_indent_preprocessor_region=no_indent
resharper_indent_statement_pars=outside
resharper_indent_typearg_angles=outside
resharper_indent_typeparam_angles=outside
resharper_keep_existing_embedded_arrangement=false
resharper_keep_existing_expr_member_arrangement=false
resharper_keep_existing_invocation_parens_arrangement=false
resharper_keep_existing_linebreaks=false
resharper_keep_existing_switch_expression_arrangement=false
resharper_place_attribute_on_same_line=false
resharper_place_expr_accessor_on_single_line=true
resharper_place_expr_method_on_single_line=true
resharper_place_expr_property_on_single_line=true
resharper_place_simple_embedded_statement_on_same_line=false
resharper_space_within_empty_braces=false
resharper_wrap_array_initializer_style=chop_always
resharper_wrap_before_extends_colon=true
resharper_wrap_before_type_parameter_langle=true
resharper_wrap_multiple_type_parameter_constraints_style=wrap_if_long
resharper_wrap_object_and_collection_initializer_style=chop_always
# ReSharper inspection severities
resharper_arrange_attributes_highlighting=suggestion
resharper_arrange_redundant_parentheses_highlighting=suggestion
resharper_enforce_if_statement_braces_highlighting=suggestion
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size=2
# JavaScript/HTML
[*.{js,ts,json,html,cshtml}]
indent_size=2
# Code files
[*.{cs,csx,vb,vbx}]
indent_size=4
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first=true
# this. preferences
dotnet_style_qualification_for_field=false:suggestion
dotnet_style_qualification_for_property=false:suggestion
dotnet_style_qualification_for_method=false:suggestion
dotnet_style_qualification_for_event=false:suggestion
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members=true:warning
dotnet_style_predefined_type_for_member_access=true:suggestion
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators=always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators=always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators=always_for_clarity:silent
dotnet_style_parentheses_in_other_operators=never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers=for_non_interface_members:silent
dotnet_style_readonly_field=true:suggestion
# Expression-level preferences
dotnet_style_object_initializer=true:warning
dotnet_style_collection_initializer=true:warning
dotnet_style_explicit_tuple_names=true:suggestion
dotnet_style_null_propagation=true:suggestion
dotnet_style_coalesce_expression=true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method=true:suggestion
dotnet_style_prefer_inferred_tuple_names=true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names=true:suggestion
dotnet_style_prefer_auto_properties=true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment=true:suggestion
dotnet_style_prefer_conditional_expression_over_return=true:suggestion
dotnet_style_prefer_compound_assignment=true:suggestion
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization=pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity=warning
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols=constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style=pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds=field
dotnet_naming_symbols.constant_fields.applicable_accessibilities=*
dotnet_naming_symbols.constant_fields.required_modifiers=const
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = warning
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.private_or_internal_static_field_should_be_private_or_internal_static_with_prefix.severity = warning
dotnet_naming_rule.private_or_internal_static_field_should_be_private_or_internal_static_with_prefix.symbols = private_or_internal_static_field
dotnet_naming_rule.private_or_internal_static_field_should_be_private_or_internal_static_with_prefix.style = private_or_internal_static_with_prefix
dotnet_naming_rule.private_or_internal_field_should_be_private_prefix.severity = warning
dotnet_naming_rule.private_or_internal_field_should_be_private_prefix.symbols = private_or_internal_field
dotnet_naming_rule.private_or_internal_field_should_be_private_prefix.style = private_prefix
dotnet_naming_rule.asyncmethods_should_be_ends_with_async.severity = warning
dotnet_naming_rule.asyncmethods_should_be_ends_with_async.symbols = asyncmethods
dotnet_naming_rule.asyncmethods_should_be_ends_with_async.style = ends_with_async
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field
dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected
dotnet_naming_symbols.private_or_internal_field.required_modifiers =
dotnet_naming_symbols.private_or_internal_static_field.applicable_kinds = field
dotnet_naming_symbols.private_or_internal_static_field.applicable_accessibilities = internal, private, private_protected
dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = static
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
dotnet_naming_symbols.asyncmethods.applicable_kinds = delegate, method, local_function
dotnet_naming_symbols.asyncmethods.applicable_accessibilities = *
dotnet_naming_symbols.asyncmethods.required_modifiers = async
# Naming styles
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.private_or_internal_static_with_prefix.required_prefix = _
dotnet_naming_style.private_or_internal_static_with_prefix.required_suffix =
dotnet_naming_style.private_or_internal_static_with_prefix.word_separator =
dotnet_naming_style.private_or_internal_static_with_prefix.capitalization = pascal_case
dotnet_naming_style.private_prefix.required_prefix = _
dotnet_naming_style.private_prefix.required_suffix =
dotnet_naming_style.private_prefix.word_separator =
dotnet_naming_style.private_prefix.capitalization = camel_case
dotnet_naming_style.ends_with_async.required_prefix =
dotnet_naming_style.ends_with_async.required_suffix = Async
dotnet_naming_style.ends_with_async.word_separator =
dotnet_naming_style.ends_with_async.capitalization = pascal_case
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types=true:suggestion
csharp_style_var_when_type_is_apparent=true:suggestion
csharp_style_var_elsewhere=true:suggestion
# Expression-bodied members
csharp_style_expression_bodied_methods=when_on_single_line:suggestion
csharp_style_expression_bodied_constructors=when_on_single_line:suggestion
csharp_style_expression_bodied_operators=when_on_single_line:suggestion
csharp_style_expression_bodied_properties=true:suggestion
csharp_style_expression_bodied_indexers=true:suggestion
csharp_style_expression_bodied_accessors=true:suggestion
csharp_style_expression_bodied_lambdas=true:suggestion
csharp_style_expression_bodied_local_functions=true:suggestion
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check=true:suggestion
csharp_style_pattern_matching_over_as_with_null_check=true:suggestion
# Null-checking preferences
csharp_style_throw_expression=true:warning
csharp_style_conditional_delegate_call=true:warning
# Modifier preferences
csharp_preferred_modifier_order=public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces=false:suggestion
csharp_style_deconstructed_variable_declaration=true:suggestion
csharp_prefer_simple_default_expression=true:warning
csharp_style_pattern_local_over_anonymous_function=true:suggestion
csharp_style_inlined_variable_declaration=true:suggestion
# Prefer C# 8.0 Indexing Features
csharp_style_prefer_index_operator=true:suggestion
csharp_style_prefer_range_operator=true:suggestion
csharp_style_deconstructed_variable_declaration=true:suggestion
csharp_style_pattern_local_over_anonymous_function=true:suggestion
csharp_using_directive_placement=outside_namespace:suggestion
csharp_prefer_static_local_function=true:suggestion
csharp_prefer_simple_using_statement=true:suggestion
csharp_style_prefer_switch_expression=true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace=all
csharp_new_line_before_else=true
csharp_new_line_before_catch=true
csharp_new_line_before_finally=true
csharp_new_line_before_members_in_object_initializers=true
csharp_new_line_before_members_in_anonymous_types=true
csharp_new_line_between_query_expression_clauses=true
# Indentation preferences
csharp_indent_case_contents=true
csharp_indent_switch_labels=true
csharp_indent_labels=flush_left
csharp_indent_block_contents=true
csharp_indent_braces=false
csharp_indent_case_contents_when_block=true
# Space preferences
csharp_space_after_cast=false
csharp_space_after_keywords_in_control_flow_statements=true
csharp_space_between_method_call_parameter_list_parentheses=false
csharp_space_between_method_declaration_parameter_list_parentheses=false
csharp_space_between_parentheses=false
csharp_space_before_colon_in_inheritance_clause=true
csharp_space_after_colon_in_inheritance_clause=true
csharp_space_around_binary_operators=before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses=false
csharp_space_between_method_call_name_and_opening_parenthesis=false
csharp_space_between_method_call_empty_parameter_list_parentheses=false
# Wrapping preferences
csharp_preserve_single_line_statements=false
csharp_preserve_single_line_blocks=true
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order=Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion

13
.gitattributes vendored
View File

@@ -1,13 +0,0 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
* text eol=lf
# Denote all files that are truly binary and should not be modified.
*.eot binary
*.ico binary
*.jpg binary
*.otf binary
*.png binary
*.ttf binary
*.woff binary
*.woff2 binary

View File

@@ -1,33 +0,0 @@
**Please use the search bar** at the top of the page and make sure you are not creating an already submitted issue.
Check closed issues as well, because your issue may have already been fixed.
Please read our [Contributing Guidelines](https://github.com/Jackett/Jackett/blob/master/CONTRIBUTING.md) before submitting your issue to ensure a prompt response to your bug.
### Environment
**OS**:
**.Net Runtime**: [.Net-Core/.Net-Framework/Mono]
**.Net Version**:
**Jackett Version**:
**Last Working Jackett Version**:
**Are you using a proxy or VPN?** [yes/no]
### Description
[List steps to reproduce the error and details on what happens and what you expected to happen]
### Logged Error Messages
[Place any relevant error messages you noticed from the logs here.]
[Make sure you attach the full logs with your personal information removed in case we need more information]
### Screenshots
[Place any screenshots of the issue here if needed]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 KiB

View File

@@ -1,7 +0,0 @@
Duplicate of #{{ chosenIssue.number }}
Hi @{{ payload.sender.login }},
This issue looks similar to #{{ chosenIssue.number }}.
To prevent issue tracker clutter, this issue will now be closed. If you feel this issue isn't a duplicate of #{{ chosenIssue.number }}, then feel free to post a comment on this issue stating why it's not a duplicate. Your comment will automatically re-open this issue.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,32 +0,0 @@
Hi @{{ payload.sender.login }},
You've created an issue, but haven't provided any details to allow the community to assist you. To prevent issue tracker clutter, this issue will now be closed. Please provide the information needed below and your comment will automatically re-open this issue.
### Environment
**OS**:
**.Net Runtime**: [.Net-Core/.Net-Framework/Mono]
**.Net Version**:
**Jackett Version**:
**Last Working Jackett Version**:
**Are you using a proxy or VPN?** [yes/no]
### Description
[List steps to reproduce the error and details on what happens and what you expected to happen]
### Logged Error Messages
[Place any relevant error messages you noticed from the logs here.]
[Make sure you attach the full logs with your personal information removed in case we need more information]
### Screenshots
[Place any screenshots of the issue here if needed]

View File

@@ -1,3 +0,0 @@
Hi @{{ payload.data.user.login }},
No response has been received for {{ days }} days. To prevent issue tracker clutter, this issue will now be closed. To re-open the issue, please provide the information requested and the issue will automatically re-open.

View File

@@ -1,7 +0,0 @@
Hi @{{ payload.pull_request.user.login }},
Thanks for your contribution to Jackett!
If you are adding a new indexer, please ensure that you've added it to the readme as well
A human will be along soon to review

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

4
.gitignore vendored
View File

@@ -194,7 +194,3 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
/tools
*.DS_Store
.idea/
launchSettings.json

21
Build.bat Normal file
View File

@@ -0,0 +1,21 @@
rmdir /s /q build
rmdir /s /q Output
cd src
Msbuild Jackett.sln /t:Clean,Build /p:Configuration=Release
cd ..
xcopy src\Jackett.Console\bin\Release Build\ /e /y
copy /Y src\Jackett.Service\bin\Release\JackettService.exe build\JackettService.exe
copy /Y src\Jackett.Service\bin\Release\JackettService.exe.config build\JackettService.exe.config
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe build\JackettTray.exe
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe.config build\JackettTray.exe.config
copy /Y LICENSE build\LICENSE
copy /Y README.md build\README.md
cd build
del *.pdb
del *.xml
cd ..
iscc Installer.iss

View File

@@ -1,200 +0,0 @@
# Contributing to Jackett
So, you've decided you want to help make Jackett a better program for everyone. Not everyone chooses to help, so we thank you for your decision.
In order to help us make the most of your contribution please take the time to read these contributing guidelines.
These are just guidelines, not hard rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
## Ways you can help
- [Getting Started](#getting-started)
- [Troubleshooting](#troubleshooting)
- [Reporting a bug](#reporting-a-bug)
- [Adding a new tracker](#adding-a-new-tracker)
- [Contributing Code](#contributing-code)
- [Setting up your environment](#setting-up-your-environment)
- [Coding style](#coding-style)
- [Getting your code accepted & pull requests](#pull-requests)
# Getting Started
Now that you've decided you want to help us make Jackett a better program the big question is: Where do you start?
Why right here of course. You can help in several ways, from finding and reporting bugs, to adding new trackers,
to fixing bugs in the program code itself. Below, we outline the steps needed to file your first bug report.
## Troubleshooting
Before you submit a bug report, it's important to make sure it's not already a known issue,
and to make sure it's a bug we can find and fix quickly.
These troubleshooting tips will help make sure your bug report is high quality and can be fixed quickly.
**Update your Jackett to the latest version**
Before you submit a bug-report or do any other troubleshooting, make sure your Jackett is the latest release version.
We are releasing bug fixes almost daily, so your issue may have been fixed already.
Bugs that are submitted without being on the latest version may be closed.
**Error "An error occurred while sending the request: Error: TrustFailure (A call to SSPI failed, see inner exception.)"**
This is often caused by missing CA certificates.
Try reimporting the certificates in this case:
- On Linux (as user root): `wget -O - https://curl.haxx.se/ca/cacert.pem | cert-sync /dev/stdin`
- On macOS: `curl -sS https://curl.haxx.se/ca/cacert.pem | cert-sync --user /dev/stdin`
**Tracker isn't working**
If you are experiencing an issue with a tracker, then:
- Use your browser to check you can access the site directly, and if a login is required,
check you can login and that you do not have any outstanding account issues.
- If you haven't already, try upgrading to the latest version of Jackett.
- If it is still not working for you, then a **full enhanced log must be included**.
**Enable enhanced logging**
- You can get *enhanced* logging with the command line switches `-t -l` or by enabling `Enhanced logging` via the web interface
(followed by clicking on the `Apply Server Settings` button).
- These enhanced logs are necessary for us to quickly track down your bug and get a fix implemented in code.
- Make sure you remove your username/password/cookies from the log files before submitting them with your issue.
- The logfiles (log.txt/updater.txt) are stored on Windows in `%ProgramData%\Jackett`, on Linux/macOS in `~/.config/Jackett/`,
and on FreeBSD in `/usr/local/jackett`.
## Reporting a Bug
Once you have your enhanced logs and you are still unable to resolve your issue yourself, now it's time to prepare to submit a bug report!
Before you submit your report, make sure you've searched open *and* closed bugs to see if someone's already informed us of your issue.
If your search doesn't help you fix your issue and you can't find a similar bug already listed, then you get to make a new issue.
Your issue should have the following information.
- **Descriptive Title** - The title of your bug should include keywords and a descriptive summary of what you're experiencing
to help others avoid duplicating your bug report
- Keywords in the title should be as follows:
- Tracker bugs should start with the tracker in brackets e.g. [**AnimeBytes**]
- Feature requests should start with [**REQ**]
- New trackers should begin with [**New**] and the tracker type [**Public**/**Private**/**Semi-Private**] e.g. **[New][Public] ThePirateBay**
- **Environment Details** - These are things like your OS version, Jackett type and version, mono/.Net-core/framework version(s).
These are asked for by the issue template when you create a new issue on GitHub.
- **Steps** to cause the problem, if applicable. These should be specific and repeatable.
- **What happens** when you take the steps and **what you expected to happen**
- **Error messages** and/or screenshots of the issue.
- The **last working version** if it's applicable. Tracker issues normally don't need this information.
- An attached copy of your **enhanced logs**. Don't forget to remove usernames/passwords/API-keys from the logs.
We'll be working on making sure these are automatically censored in the future.
- Any other **relevant details** you can think of. The more information we have, the quicker we can solve the problem.
## Adding a New Tracker
Jackett's framework typically allows our team and volunteering developers to implement new trackers in a couple of hours
Depending on logic complexity, there are two common ways new trackers are implemented:
1. simple [definitions](http://github.com/Jackett/Jackett/tree/master/src/Jackett.Common/Definitions) (.yml / YAML)
2. advanced (native) [indexers](http://github.com/Jackett/Jackett/tree/master/src/Jackett.Common/Indexers) (.cs / C#)
Read more about the [simple definition format](https://github.com/Jackett/Jackett/wiki/Definition-format).
# Contributing Code
While reporting the bugs is super helpful since you can't fix bugs you don't know about, they don't get fixed unless someone goes in and fixes them.
Luckily, you're a developer who wants to help us do just that. Thanks!
We really need more developers working on Jackett, no matter their skill level or walk of life.
We've developed the guide below to make sure we're all on the same page because this makes reading and fixing code much simpler, faster, and less bug-prone.
## Setting up your environment
The following guide assumes you've never worked with a Visual Studio project with GitHub before.
This will give you the minimum necessary tools to get started. There are plenty of optional tools that may help you, but we won't cover those here.
- The guide is currently only geared towards developing on Windows using Visual Studio Community 2019.
If you use something else, please add it here for others.
<details open=true> <summary> Windows </summary>
<details open=true> <summary> Visual Studio 2019 </summary>
- Install [Visual Studio Community 2019](http://visualstudio.com) for free.
- About 2GB download. 8GB installed.
- Make sure it includes the following Workloads/Components:
- .Net Desktop Development
- .Net Core Cross-Platform Development
- GitHub extension for Visual Studio
- [Connect and synchronize your forked repository to Visual Studio](https://doc.fireflymigration.com/working-with-github-fork-in-visual-studio.html)
- Open `Tools -> NuGet Package Manager -> Package Manager Console`
- From the PMC, run `dotnet tool install -g dotnet-format` and `dotnet restore`
- Run `Build -> Rebuild Solution` to restore NuGet packages
- Ensure `Jackett.Server` is the Startup Project (instead of `Jackett.Service`), and the Run Target (instead of `IIS Express`)
</details>
</details>
## Coding Style
Now that you're ready to code, it's time to teach you our style guidelines. This style guide helps our code stay readable and bug-free.
You can see the full details in the [Editor Config](.editorconfig) file.
Running `dotnet format` from the Package Manager Console will apply the style guide to the solution and is required before any pull request will be accepted.
- Whitespace
- Indenting is done with 4 spaces
- No whitespace at the end of lines
- All files have a final newline
- Unix style new lines for committed code
- Spaces around all non-unary operators
- Braces
- Opening brace on its own line
- Single line statements do not use braces
- If any part of an `if ... else if ... else` block needs braces, all blocks will use braces
- Naming
- `interface` names begin with I and are `PascalCase`
- `private` variables begin with _ and are `camelCase`
- `private static` variables begin with s_ and are `camelCase`
- local variables are `camelCase`
- `async` function names end with Async
- all others are `PascalCase`
- Others
- Prefer `var` for declarations
- Prefer modern language enhancements (C#7, C#8 features)
- switch expressions
- range operator
- using statements
- `default` over `default(T)`
- Prefer conditional access `?.` and null coalescing `??` over null checks
- Prefer pattern matching
- Prefer expression bodies
- Avoid `this` qualifier
- `using` statements go outside namespace declaration and are sorted:
- `using System`
- `using System.*` alphabetically
- all others alphabetically
- Prefer explicit variable modifiers: `private`, `public`, `protected`
- Prefer `readonly` and `const` variables when appropriate
## Pull Requests
At this point, you've found the bug, fixed it, tested that the bug is gone, and you haven't broken anything else in the process.
Now it's time to share your code with everyone else so we can all enjoy a better version of the program.
Here's what you need to do to give your pull request the best chance at a timely review and maximize that it will be accepted.
- Make sure your code follows GitHub and Jackett's standards and practices.
- Your changes should be made in a new branch based on `master` not directly on your `master` branch
- Your commit messages should start with a capital letter, be in the singular imperative voice, and do not end with punctuation marks, e.g.:
- Fix login handling for xxx tracker
- Add feature yyy
- Remove dead tracker fff
- Run `dotnet format` from the Package Manager Console (found in `Tools -> NuGet Package Manager` or `View -> Other Windows`)
- If your branch falls out of sync and has merge conflicts with the Jackett official `master`
[rebase](https://mohitgoyal.co/2018/04/18/working-with-git-and-visual-studio-use-git-rebase-inside-visual-studio/) your fix before submission.
- If you deleted, moved, or renamed any files/folders, be sure to add the old file/folder path to the appropriate array in `Jacket.Updater/Program.cs`
- If you added or renamed a tracker, update the README to include the new name
- [Squash your local commits](https://github.com/spottedmahn/my-blog/issues/26)
- Push your commit branch to your fork on GitHub.
- Create your Pull Request
- You can do this from the GitHub website or from the GitHub window in Visual Studio.
- Give your Pull Request a descriptive title
- Include keywords like `[New Tracker]` or `[Feature]` at the beginning of the title
- Include any open tickets this Pull Request should fix in the description. **Do not** put ticket numbers in the title.
We will be by when we can to review your Pull Request.

View File

@@ -2,9 +2,9 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Jackett"
#define MyAppVersion GetFileVersion(MyFileForVersion)
#define MyAppPublisher "Jackett"
#define MyAppURL "https://github.com/Jackett/Jackett"
#define MyAppVersion "0.5"
#define MyAppPublisher "Jackett Inc."
#define MyAppURL "https://github.com/zone117x/Jackett"
#define MyAppExeName "JackettTray.exe"
[Setup]
@@ -19,17 +19,14 @@ AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={commonappdata}\{#MyAppName}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputBaseFilename={#MyOutputFilename}
SetupIconFile=src\Jackett.Tray\jackett.ico
UninstallDisplayIcon={commonappdata}\Jackett\{#MyAppExeName}
VersionInfoVersion={#MyAppVersion}
UninstallDisplayName={#MyAppName}
OutputBaseFilename=setup
SetupIconFile=src\Jackett.Console\jackett.ico
UninstallDisplayIcon={app}\JackettConsole.exe
Compression=lzma
SolidCompression=yes
DisableDirPage=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -39,24 +36,26 @@ Name: "windowsService"; Description: "Install as a Windows Service"
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "{#MySourceFolder}\*"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Build\JackettTray.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "Build\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{commonappdata}\Jackett\{#MyAppExeName}"
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{commonappdata}\Jackett\{#MyAppExeName}"; Tasks: desktopicon
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{commonappdata}\Jackett\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated runhidden;
Filename: "{commonappdata}\Jackett\JackettConsole.exe"; Parameters: "--ReserveUrls"; Flags: waituntilterminated runhidden;
Filename: "{commonappdata}\Jackett\JackettConsole.exe"; Parameters: "--Install"; Flags: waituntilterminated runhidden; Tasks: windowsService
Filename: "{commonappdata}\Jackett\JackettConsole.exe"; Parameters: "--Start"; Flags: waituntilterminated runhidden; Tasks: windowsService
Filename: "{commonappdata}\Jackett\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Run]
Filename: "{app}\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated;
Filename: "{app}\JackettConsole.exe"; Parameters: "--ReserveUrls"; Flags: waituntilterminated;
Filename: "{app}\JackettConsole.exe"; Parameters: "--MigrateSettings"; Flags: waituntilterminated;
Filename: "{app}\JackettConsole.exe"; Parameters: "--Install"; Flags: waituntilterminated; Tasks: windowsService
Filename: "{app}\JackettConsole.exe"; Parameters: "--Start"; Flags: waituntilterminated; Tasks: windowsService
[UninstallRun]
Filename: "{commonappdata}\Jackett\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated skipifdoesntexist runhidden
Filename: "{sys}\taskkill.exe"; Parameters: "/f /im {#MyAppExeName}"; Flags: waituntilterminated skipifdoesntexist runhidden
Filename: "{sys}\taskkill.exe"; Parameters: "/f /im JackettConsole.exe"; Flags: waituntilterminated skipifdoesntexist runhidden
Filename: "{app}\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated skipifdoesntexist

782
README.md
View File

@@ -1,751 +1,67 @@
# Jackett
[![GitHub issues](https://img.shields.io/github/issues/Jackett/Jackett.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/Jackett/Jackett.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/pulls)
[![Build Status](https://dev.azure.com/Jackett-project/Jackett/_apis/build/status/Jackett.Jackett?branchName=master)](https://dev.azure.com/jackett/jackett/_build/latest?definitionId=1&branchName=master)
[![GitHub Releases](https://img.shields.io/github/downloads/Jackett/Jackett/total.svg?maxAge=60&style=flat-square)](https://github.com/Jackett/Jackett/releases/latest)
[![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/jackett.svg?maxAge=60&style=flat-square)](https://hub.docker.com/r/linuxserver/jackett/)
[![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60&style=flat-square)](https://discord.gg/J865QuA)
Use just about any tracker with Sonarr
This project is a new fork and is recruiting development help. If you are able to help out please contact us.
### API Access to your favorite trackers
Please see our [troubleshooting and contributing guidelines](CONTRIBUTING.md) before submitting any issues or pull requests
This software creates a [Torznab](https://github.com/Sonarr/Sonarr/wiki/Implementing-a-Torznab-indexer) API server on your machine that any Torznab enabled software can consume. Jackett works as a proxy server: it translates Torznab queries into tracker-site-specific http queries, parses the html response into Torznab results, then sends results back to the requesting software.
Jackett works as a proxy server: it translates queries from apps ([Sonarr](https://github.com/Sonarr/Sonarr), [Radarr](https://github.com/Radarr/Radarr), [SickRage](https://sickrage.github.io/), [CouchPotato](https://couchpota.to/), [Mylar](https://github.com/evilhero/mylar), [Lidarr](https://github.com/lidarr/lidarr), [DuckieTV](https://github.com/SchizoDuckie/DuckieTV), [qBittorrent](https://www.qbittorrent.org/), [Nefarious](https://github.com/lardbit/nefarious) etc.) into tracker-site-specific http queries, parses the html response, then sends results back to the requesting software. This allows for getting recent uploads (like RSS) and performing searches. Jackett is a single repository of maintained indexer scraping & translation logic - removing the burden from other apps.
Currently [Sonarr](https://sonarr.tv/) is the only software that uses Torznab. [Couchpotato](https://couchpota.to/) will hopefully get Torznab support in the future.
Developer note: The software implements the [Torznab](https://github.com/Sonarr/Sonarr/wiki/Implementing-a-Torznab-indexer) (with [nZEDb](https://github.com/nZEDb/nZEDb/blob/dev/docs/newznab_api_specification.txt) category numbering) and [TorrentPotato](https://github.com/RuudBurger/CouchPotatoServer/wiki/Couchpotato-torrent-provider) APIs.
### Download
Download in the [Releases page](https://github.com/zone117x/Jackett/releases)
### Supported Systems
* Works on Windows by default
* Works on Linux and OS X using Mono. See instructions below...
### Instructions for Mono
* Install Mono: http://www.mono-project.com/download/
* *For MoreThanTV & ThePirateBay* install libcurl-dev for your system, [tutorial](http://curl.haxx.se/dlwiz/?type=devel)
* For apt-get systems its simply: `apt-get install libcurl4-openssl-dev`
#### Supported Systems
* Windows 7SP1 or greater
* Linux [supported operating systems here](https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1-supported-os.md#linux)
* macOS 10.13 or greater
### Running Jackett
<details> <summary> <b> Supported Public Trackers </b> </summary>
On Windows the recommended way of running Jackett is to install it as a windows service. When installed as a service the tray icon acts as a way to open/start/stop Jackett. If you opted to not install it as a service then Jackett will run its web server from the tray tool.
* 1337x
* 7torrents
* AcademicTorrents
* ACG.RIP
* ACGsou
* Anidex
* Anime Tosho
* AniRena
* AudioBook Bay (ABB)
* Badass Torrents
* BigFANGroup
* BitRu
* BitTorrent.AM
* BT.etree
* BTDB
* BTDIGG
* BTeye
* BTSOW
* Cili180
* ConCen
* Corsaro.red
* cpasbien
* cpasbienClone
* Demonoid
* dmhy
* EliteTorrent.biz
* EstrenosDTL
* ETTV
* EXT Torrents
* ExtraTorrent.cd
* EZTV
* Filebase
* FireBit
* Frozen Layer
* GamesTorrents
* GkTorrent
* GloDLS
* HDReactor
* Horrible Subs
* IBit
* Idope
* Il CorSaRo Blu
* Il Corsaro Nero <!-- maintained by bonny1992 -->
* Internet Archive (archive.org)
* Isohunt2
* iTorrent
* KickAssTorrent (kat.li)
* KickAssTorrent (KATcr)
* Legit Torrents
* LePorno
* LimeTorrents
* LinuxTracker
* MacTorrents
* Magnet4You
* MagnetDL
* MejorTorrent <!-- maintained by ivandelabeldad -->
* Monova
* MovCr
* MoviesDVDR
* MyPornClub
* Newpct (aka: tvsinpagar, descargas2020, torrentlocura, torrentrapid, tumejortorrent, pctnew, etc)
* Newstudio
* Nitro
* NNTT
* NoName Club (NNM-Club)
* Nyaa-Pantsu
* Nyaa.si
* OneJAV
* OxTorrent
* ParnuXi
* PiratBit
* Pirateiro
* PornLeech
* PornoLive
* PornoRip
* PornoTor
* ProStyleX
* Rapidzona
* RARBG
* Rus-media
* RuTor
* RuTracker.RU
* Seedpeer
* shokweb
* ShowRSS
* SkyTorrentsClone
* SolidTorrents
* sosulki
* sukebei-Pantsu
* sukebei.Nyaa.si
* TFile
* The Pirate Bay (TPB)
* Tokyo Tosho
* TopNow
* Torlock
* TOROS
* Torrent Downloads (TD)
* Torrent Oyun indir
* torrent-pirat
* Torrent4You
* Torrent9
* Torrent9Clone
* TorrentDownload
* TorrentFunk
* TorrentGalaxy (TGx)
* TorrentKitty
* TorrentParadise
* TorrentProject2
* TorrentRex
* TorrentQuest
* Torrents.csv
* Torrentv
* TorrentView
* Torrentz2
* Underverse
* UnionDHT
* xxxtor
* YourBittorrent
* YTS.ag
* zetorrents
* Zooqle
</details>
Jackett can also be run from the command line (See --help for switches) using JackettConsole.exe if you would like to see log messages where the service and tray isn't running. On Linux / OSX you would need to run the console using "mono JackettConsole.exe".
<details> <summary> <b> Supported Semi-Private Trackers </b> </summary>
* AlexFilm
* AniDUB
* ArenaBG
* BaibaKo
* BookTracker
* CasStudioTV
* Crazy's Corner
* CzTorrent
* DXP (Deaf Experts)
* Deildu
* EniaHD
* Erzsebet
* ExKinoRay
* ExtremlymTorrents
* FilmsClub
* Gay-Torrents.net
* Gay-Torrents.org
* HD Dolby
* HamsterStudio
* IV-Torrents
* KinoNaVse100
* Kinozal
* Korsar
* LostFilm.tv
* MVGroup Forum
* MVGroup Main
* Marine Tracker
* Metal Tracker
* MuziekFrabriek
* NetHD (VietTorrent)
* Pornolab
* RiperAM
* RockBox
* RuTracker
* Rustorka
* Sharewood
* SkTorrent
* SoundPark
* Toloka.to
* Torrent-Explosiv
* Torrents-Local
* TribalMixes
* Union Fansub
* YggTorrent (YGG)
* Ztracker
</details>
### Supported Trackers
* [AlphaRatio](https://alpharatio.cc/)
* [AnimeBytes](https://animebytes.tv/)
* [BakaBT](http://bakabt.me/)
* [bB](http://reddit.com/r/baconbits)
* [BeyondHD](https://beyondhd.me/)
* [BIT-HDTV](https://www.bit-hdtv.com)
* [BitMeTV](http://www.bitmetv.org/)
* [FrenchTorrentDb](http://www.frenchtorrentdb.com/)
* [Freshon](https://freshon.tv/)
* [HD-Space](https://hd-space.org/)
* [HD-Torrents.org](https://hd-torrents.org/)
* [IPTorrents](https://iptorrents.com/)
* [MoreThan.tv](https://morethan.tv/)
* [pretome](https://pretome.info)
* [PrivateHD](https://privatehd.to/)
* [RARBG](https://rarbg.com)
* [SceneAccess](https://sceneaccess.eu/login)
* [SceneTime](https://www.scenetime.com/)
* [ShowRSS](https://showrss.info/)
* [Strike](https://getstrike.net/)
* [T411](http://www.t411.io/)
* [The Pirate Bay](https://thepiratebay.se/)
* [TorrentDay](https://torrentday.eu/)
* [TorrentLeech](http://www.torrentleech.org/)
* [TorrentShack](http://torrentshack.me/)
* [Torrentz](https://torrentz.eu/)
<details> <summary> <b> Supported Private Trackers </b> </summary>
* 0day.kiev
* 2 Fast 4 You
* 3D Torrents (3DT)
* 3evils
* 4thD (4th Dimension)
* 52PT
* 720pier
* AST4u
* Abnormal
* Acid Lounge (A-L)
* Aftershock
* AlphaRatio (AR)
* AmigosShareClub
* AnimeBytes (AB)
* AnimeTorrents (AnT)
* Anthelion
* Araba Fenice (Phoenix)
* Asgaard (AG)
* AsianCinema
* AudioNews (AN)
* Audiobook Torrents (ABT)
* Avistaz (AsiaTorrents)
* Awesome-HD (AHD)
* BIGTorrent
* BIT-HDTV
* BJ-Share (BJ)
* BRObits
* BTGigs (TG)
* BTNext (BTNT)
* BTSCHOOL
* Back-ups
* BaconBits (bB)
* BakaBT
* BeiTai
* BeyondHD (BHD)
* BiT-TiTAN
* Bibliotik
* BigTower
* Bit-City Reloaded
* BitHUmen
* BitTorrentFiles
* BitTurk
* Bithorlo (BHO)
* Bitspyder
* BlueBird
* Blutopia (BLU)
* Boxing Torrents
* Brasil Tracker
* BroadCity
* BroadcastTheNet (BTN)
* BrokenStones
* CCFBits
* CGPeers
* CHDBits
* Carpathians
* CartoonChaos (CC)
* CasaTorrent
* ChannelX
* CinemaMovies
* CinemaZ (EuTorrents)
* Cinemageddon
* Cinematik
* Classix
* Concertos
* CrazyHD
* CrazySpirits
* CrnaBerza
* DXDHD
* DanishBits (DB)
* Das Unerwartete
* DataScene (DS)
* DesiReleasers
* DesiTorrents
* Diablo Torrent
* DigitalCore
* DigitalHive
* DivTeam
* DivxTotal
* DocumentaryTorrents (DT)
* Downloadville
* Dragonworld Reloaded
* EbookParadijs
* Ebooks-Shares
* EfectoDoppler
* Elite-Tracker
* Empornium (EMP)
* EpubLibre
* Ethor.net (Thor's Land)
* ExoticaZ (YourExotic)
* ExtremeTorrents
* FANO.IN
* Fantastic Heaven
* FeedUrNeed (FuN)
* Femdomcult
* FileList (FL)
* Film-Paleis
* FinVip
* FocusX
* FreeTorrent
* FullMixMusic
* FunFile (FF)
* FunkyTorrents (FT)
* Fuzer (FZ)
* GAYtorrent.ru
* GFXPeers
* Galeriens (LaPauseTorrents)
* GazelleGames (GGn)
* Generation-Free
* GigaTorrents
* GimmePeers (formerly ILT)
* GiroTorrent
* Greek Team
* HD-Bits.com
* HD-Forever (HDF)
* HD-Olimpo
* HD-Only (HDO)
* HD-Space (HDS)
* HD-Spain
* HD-Torrents (HDT)
* HD4FANS
* HDArea (HDA)
* HDBits
* HDCenter
* HDChina (HDWing)
* HDCity
* HDDisk (HDD)
* HDHome (HDBigger)
* HDME
* HDRoute
* HDSky
* HDTime
* HDTorrents.it
* HDTurk
* HDU
* HDZone
* HQSource (HQS)
* HacheDe
* Hebits
* Hon3y HD
* Horror Site
* HuSh
* ICE Torrent
* IPTorrents (IPT)
* ImmortalSeed (iS)
* Immortuos
* Insane Tracker
* JPopsuki
* Kapaki
* Karagarga
* LastFiles
* Le Saloon
* LeChaudron
* LeagueHD
* LearnFlakes
* LegacyHD (HD4Free)
* LibraNet (LN)
* LinkoManija
* LosslessClub
* M-Team TP (MTTP)
* Magico (Trellas)
* Majomparádé (TurkDepo)
* MicroBit (µBit)
* MMA-Torrents
* MoeCat
* Mononoké-BT
* MoreThanTV (MTV)
* MyAnonamouse (MAM)
* MySpleen
* NBTorrents
* NCore
* Nebulance (NBL) (TransmiTheNet)
* NetCosmo
* NetLab
* New Real World
* Norbits
* NordicBits (NB)
* Nostalgic (The Archive / VHSTAPES)
* OnlineSelfEducation
* Orpheus
* Ourbits (HDPter)
* P2PBG
* P2PElite
* PT99
* PTFiles (PTF)
* PThome
* PWTorrents (PWT)
* Partis
* PassThePopcorn (PTP)
* Peers.FM
* PiXELHD (PxHD)
* PirateTheNet (PTN)
* PixelCove (Ultimate Gamer)
* Pleasuredome
* PolishSource (PS)
* PolishTracker
* PornBits (PB)
* Pornbay
* Pretome
* PrivateHD (PHD)
* ProAudioTorrents (PAT)
* Psytorrents
* PuntoTorrent
* R3V WTF!
* RPTorrents
* Racing4Everyone (R4E)
* RacingForMe (RFM)
* RainbowNation Sharing (RNS)
* Red Star Torrent (RST)
* Redacted (PassTheHeadphones)
* RetroFlix
* RevolutionTT
* RoDVD (Cinefiles)
* Romanian Metal Torrent (RMT)
* SDBits
* SceneFZ
* SceneHD
* ScenePalace (SP)
* SceneRush
* SceneTime
* Secret Cinema
* SeedFile (SF)
* ShareSpaceDB
* ShareUniversity
* Shareisland
* Shazbat
* Shellife (SL)
* SiamBIT
* SnowPT (SSPT)
* SpaceTorrent
* SpeedCD
* SpeedTorrent Reloaded
* Spirit of Revolution
* SportHD
* SportsCult
* SpringSunday
* SuperBits (SBS)
* TEKNO3D
* TLFBits
* TOrrent-tuRK (TORK)
* TTsWEB
* TV Chaos UK (TVCUK)
* TV-Vault
* TVstore
* TakeaByte
* Tapochek
* Tasmanit
* TeamHD
* TeamOS
* TellyTorrent
* TenYardTorrents (TYT)
* The Falling Angels (TFA)
* The Geeks
* The Horror Charnel (THC)
* The New Retro
* The Occult
* The Place
* The Shinning (TsH)
* The Show
* The Vault
* The-Madhouse
* TheAudioScene
* TheEmpire (TE)
* ToTheGlory
* Torrent Network (TN)
* Torrent Sector Crew (TSC)
* Torrent-Syndikat
* Torrent.LT
* TorrentBD
* TorrentBytes (TBy)
* TorrentCCF (TCCF)
* TorrentDay (TD)
* TorrentFactory
* TorrentHR
* TorrentHeaven
* TorrentLeech (TL)
* TorrentLeech.pl
* TorrentSeeds (TS)
* Torrentech (TTH)
* Torrenting (TT)
* Torrentland
* TotallyKids (TK)
* TranceTraffic
* Trezzor
* TurkTorrent (TT)
* Twilight Torrents
* Twilights Zoom
* U-Torrents
* U2 (U2分享園@動漫花園)
* UHDBits
* UnionGang
* UnlimitZ
* Vizuk
* WDT (Wrestling Desires Torrents / Ultimate Wrestling Torrents)
* World-In-HD
* World-of-Tomorrow
* XSpeeds (XS)
* XWT-Classics
* XWTorrents (XWT)
* Xthor
* XtreMeZone (MYXZ)
* XtremeFile
* Zamunda.net
* Zelka.org
* eShareNet
* eStone (XiDER, BeLoad)
* inPeril
* myAmity
* notwhat.cd
* u-torrents (SceneFZ)
* x-ite.me (XM)
* xBytesV2
</details>
### Additional Trackers
Jackett's framework allows me (and any other volunteering dev) to implement just about any new tracker in 15-60 minutes. If you'd like support for a new tracker then feel free to leave a request on the [issues page](https://github.com/zone117x/Jackett/issues) or contact me on IRC (see below).
Trackers marked with [![(invite needed)][inviteneeded]](#) have no active maintainer and are missing features or are broken. If you have an invite for them please send it to garfieldsixtynine -at- gmail.com to get them fixed/improved.
### Contact & Support
I can be contact on IRC at [irc.freenode.net#jackett](http://webchat.freenode.net/?channels=#jackett) & [irc.freenode.net#sonarr](http://webchat.freenode.net/?channels=#sonarr)
### Aggregate indexers
### Screenshots
A special "all" indexer is available at `/api/v2.0/indexers/all/results/torznab`.
It will query all configured indexers and return the combined results.
If your client supports multiple feeds it's recommended to add each indexer directly instead of using the all indexer.
Using the all indexer has no advantages (besides reduced management overhead), only disadvantages:
* you lose control over indexer specific settings (categories, search modes, etc.)
* mixing search modes (IMDB, query, etc.) might cause low-quality results
* indexer specific categories (>= 100000) can't be used.
* slow indexers will slow down the overall result
* total results are limited to 1000
To get all Jackett indexers including their capabilities you can use `t=indexers` on the all indexer. To get only configured/unconfigured indexers you can also add `configured=true/false` as a query parameter.
## Installation on Windows
We recommend you install Jackett as a Windows service using the supplied installer. You may also download the zipped version if you would like to configure everything manually.
To get started with using the installer for Jackett, follow the steps below:
1. Download the latest version of the Windows installer, "Jackett.Installer.Windows.exe" from the [releases](https://github.com/Jackett/Jackett/releases/latest) page.
2. When prompted if you would like this app to make changes to your computer, select "yes".
3. If you would like to install Jackett as a Windows Service, make sure the "Install as Windows Service" checkbox is filled.
4. Once the installation has finished, check the "Launch Jackett" box to get started.
5. Navigate your web browser to http://127.0.0.1:9117
6. You're now ready to begin adding your trackers and using Jackett.
When installed as a service the tray icon acts as a way to open/start/stop Jackett. If you opted to not install it as a service then Jackett will run its web server from the tray tool.
Jackett can also be run from the command line if you would like to see log messages (Ensure the server isn't already running from the tray/service). This can be done by using "JackettConsole.exe" (for Command Prompt), found in the Jackett data folder: "%ProgramData%\Jackett".
## Install on Linux (AMDx64)
On most operating systems all the required dependencies will already be present. In case they are not, you can refer to this page https://github.com/dotnet/core/blob/master/Documentation/linux-prereqs.md
### Install as service
1. Download and extract the latest `Jackett.Binaries.LinuxAMDx64.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases)
2. To install Jackett as a service, open a Terminal, cd to the jackett folder and run `sudo ./install_service_systemd.sh` You need root permissions to install the service. The service will start on each logon. You can always stop it by running `systemctl stop jackett.service` from Terminal. You can start it again it using `systemctl start jackett.service`. Logs are stored as usual under `~/.config/Jackett/log.txt` and also in `journalctl -u jackett.service`.
### Run without installing as a service
Download and extract the latest `Jackett.Binaries.LinuxAMDx64.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases), open a Terminal, cd to the jackett folder and run Jackett with the command `./jackett`
### home directory
If you want to run it with a user without a /home directory you need to add `Environment=XDG_CONFIG_HOME=/path/to/folder` to your systemd file, this folder will be used to store your config files.
## Install on Linux (ARMv7 or above)
On most operating systems all the required dependencies will already be present. In case they are not, you can refer to this page https://github.com/dotnet/core/blob/master/Documentation/linux-prereqs.md
### Install as service
1. Download and extract the latest `Jackett.Binaries.LinuxARM32.tar.gz` or `Jackett.Binaries.LinuxARM64.tar.gz` (32 bit is the most common on ARM) release from the [releases page](https://github.com/Jackett/Jackett/releases)
2. To install Jackett as a service, open a Terminal, cd to the jackett folder and run `sudo ./install_service_systemd.sh` You need root permissions to install the service. The service will start on each logon. You can always stop it by running `systemctl stop jackett.service` from Terminal. You can start it again it using `systemctl start jackett.service`. Logs are stored as usual under `~/.config/Jackett/log.txt` and also in `journalctl -u jackett.service`.
### Run without installing as a service
Download and extract the latest `Jackett.Binaries.LinuxARM32.tar.gz` or `Jackett.Binaries.LinuxARM64.tar.gz` (32 bit is the most common on ARM) release from the [releases page](https://github.com/Jackett/Jackett/releases), open a Terminal, cd to the jackett folder and run Jackett with the command `./jackett`
### home directory
If you want to run it with a user without a /home directory you need to add `Environment=XDG_CONFIG_HOME=/path/to/folder` to your systemd file, this folder will be used to store your config files.
## Installation on Linux (ARMv6 or below)
1. Install [Mono 5.8](http://www.mono-project.com/download/#download-lin) or better (using the latest stable release is recommended)
* Follow the instructions on the mono website and install the `mono-devel` and the `ca-certificates-mono` packages.
* On Red Hat/CentOS/openSUSE/Fedora the `mono-locale-extras` package is also required.
2. Install libcurl:
* Debian/Ubuntu: `apt-get install libcurl4-openssl-dev`
* Redhat/Fedora: `yum install libcurl-devel`
* For other distros see the [Curl docs](http://curl.haxx.se/dlwiz/?type=devel).
3. Download and extract the latest `Jackett.Binaries.Mono.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases) and run Jackett using mono with the command `mono --debug JackettConsole.exe`.
4. (Optional) To install Jackett as a service, open the Terminal and run `sudo ./install_service_systemd_mono.sh` You need root permissions to install the service. The service will start on each logon. You can always stop it by running `systemctl stop jackett.service` from Terminal. You can start it again it using `systemctl start jackett.service`. Logs are stored as usual under `~/.config/Jackett/log.txt` and also in `journalctl -u jackett.service`.
If you want to run it with a user without a /home directory you need to add `Environment=XDG_CONFIG_HOME=/path/to/folder` to your systemd file, this folder will be used to store your config files.
Mono must be compiled with the Roslyn compiler (default), using MCS will cause "An error has occurred." errors (See https://github.com/Jackett/Jackett/issues/2704).
### Installation on Linux via Ansible
On a CentOS/RedHat 7 system: [jewflix.jackett](https://galaxy.ansible.com/jewflix/jackett)
On an Ubuntu 16 system: [chrisjohnson00.jackett](https://galaxy.ansible.com/chrisjohnson00/jackett)
## Installation on macOS
### Prerequisites
macOS 10.13 or greater
### Install as service
1. Download and extract the latest `Jackett.Binaries.macOS.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases).
2. Open the extracted folder and double-click on `install_service_macos`.
3. If the installation was a success, you can close the Terminal window.
The service will start on each logon. You can always stop it by running `launchctl unload ~/Library/LaunchAgents/org.user.Jackett.plist` from Terminal. You can start it again it using `launchctl load ~/Library/LaunchAgents/org.user.Jackett.plist`.
Logs are stored as usual under `~/.config/Jackett/log.txt`.
### Run without installing as a service
Download and extract the latest `Jackett.Binaries.macOS.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases) and run Jackett with the command `./jackett`.
## Installation using Docker
Detailed instructions are available at [LinuxServer.io Jackett Docker](https://hub.docker.com/r/linuxserver/jackett/). The Jackett Docker is highly recommended, especially if you are having Mono stability issues or having issues running Mono on your system e.g. QNAP, Synology. Thanks to [LinuxServer.io](https://linuxserver.io)
## Installation on Synology
Jackett is available as a beta package from [SynoCommunity](https://synocommunity.com/)
## Running Jackett behind a reverse proxy
When running jackett behind a reverse proxy make sure that the original hostname of the request is passed to Jackett. If HTTPS is used also set the X-Forwarded-Proto header to "https". Don't forget to adjust the "Base Path Override" Jackett option accordingly.
Example config for apache:
```
<Location /jackett>
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
ProxyPass http://127.0.0.1:9117
ProxyPassReverse http://127.0.0.1:9117
</Location>
```
Example config for Nginx:
```
location /jackett {
proxy_pass http://127.0.0.1:9117;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_redirect off;
}
```
## Configuring OMDb
This feature is used as a fallback (when using the aggregate Indexer) to get the movie/series title if only the IMDB ID is provided in the request.
To use it, please just request a free API key on [OMDb](http://www.omdbapi.com/apikey.aspx) (1,000 daily requests limit) and paste the key in Jackett
## Command line switches
You can pass various options when running via the command line:
<details> <summary> Command Line Switches </summary>
- `-i, --Install` Install Jackett windows service (Must be admin)
- `-s, --Start` Start the Jacket Windows service (Must be admin)
- `-k, --Stop` Stop the Jacket Windows service (Must be admin)
- `-u, --Uninstall` Uninstall Jackett windows service (Must be admin).
- `-r, --ReserveUrls` (Re)Register windows port reservations (Required for
listening on all interfaces).
- `-l, --Logging` Log all requests/responses to Jackett
- `-t, --Tracing` Enable tracing
- `-c, --UseClient` Override web client selection.
[automatic(Default)/httpclient/httpclient2]
- `-j, --ProxyConnection` use proxy - e.g. 127.0.0.1:8888
- `-x, --ListenPublic` Listen publicly
- `-z, --ListenPrivate` Only allow local access
- `-p, --Port` Web server port
- `-m, --MigrateSettings` Migrate settings manually (Must be an admin on Windows)
- `-n, --IgnoreSslErrors` [true/false] Ignores invalid SSL certificates
- `-d, --DataFolder` Specify the location of the data folder (Must be an admin on Windows)
- e.g. --DataFolder="D:\Your Data\Jackett\".
- Don't use this on Unix (mono) systems. On Unix just adjust the HOME directory of the user to the datadir or set the XDG_CONFIG_HOME environment variable.
- `--NoRestart` Don't restart after update
- `--PIDFile` Specify the location of PID file
- `--NoUpdates` Disable automatic updates
- `--help` Display this help screen.
- `--version` Display version information.
</details>
## Building from source
### Windows
* Install the .NET Core [SDK](https://www.microsoft.com/net/download/windows)
* Clone Jackett
* Open PowerShell and from the `src` directory, run `dotnet restore`
* Open the Jackett solution in Visual Studio 2019 (version 16.4 or above)
* Right-click on the Jackett solution and click 'Rebuild Solution' to restore NuGet packages
* Select Jackett.Server as the startup project
* In the drop-down menu of the run button select "Jackett.Server" instead of "IIS Express"
* Build/Start the project
### OSX
```bash
# manually install osx dotnet via:
https://dotnet.microsoft.com/download?initial-os=macos
# then:
git clone https://github.com/Jackett/Jackett.git
cd Jackett/src
# dotnet core version
dotnet publish Jackett.Server -f netcoreapp3.1 --self-contained -r osx-x64 -c Debug # takes care of everything
./Jackett.Server/bin/Debug/netcoreapp3.1/osx-x64/jackett # run jackett
```
### Linux
```bash
sudo apt install mono-complete nuget msbuild dotnet-sdk-3.1 # install build tools (Debian/ubuntu)
git clone https://github.com/Jackett/Jackett.git
cd Jackett/src
# dotnet core version
dotnet publish Jackett.Server -f netcoreapp3.1 --self-contained -r linux-x64 -c Debug # takes care of everything
./Jackett.Server/bin/Debug/netcoreapp3.1/linux-x64/jackett # run jackett
```
## Screenshots
![screenshot](https://raw.githubusercontent.com/Jackett/Jackett/master/.github/jackett-screenshot1.png)
![screenshot](https://raw.githubusercontent.com/Jackett/Jackett/master/.github/jackett-screenshot2.png)
![screenshot](https://raw.githubusercontent.com/Jackett/Jackett/master/.github/jackett-screenshot3.png)
[inviteneeded]: https://raw.githubusercontent.com/Jackett/Jackett/master/.github/label-inviteneeded.png
![screenshot](http://i.imgur.com/t1sVva6.png "screenshot")

View File

@@ -1,20 +0,0 @@
author "sea3pea0"
description "Upstart Script to run NzbDrone as a service on Ubuntu/Debian based systems, as well as others"
#Set username for the process. Should probably be what you use for logging in
setuid {username to run jackett}
setgid users
#This is the install directory. If you installed using a deb package or the NzbDrone Repository you do not need to change this
env DIR=/opt/Jackett
env LD_LIBRARY_PATH=/usr/local/nzbdrone/lib
start on runlevel [2345]
stop on runlevel [016]
respawn
script
chdir $DIR
exec /volume1/@appstore/Mono/usr/bin/mono --debug JackettConsole.exe
end script

View File

@@ -1,398 +0,0 @@
name: $(majorVersion).$(minorVersion).$(patchVersion)
variables:
majorVersion: 0
minorVersion: 14
patchVersion: $[counter(variables['minorVersion'], 1)] #this will reset when we bump minor
jackettVersion: $(majorVersion).$(minorVersion).$(patchVersion)
buildConfiguration: Release
netCoreFramework: netcoreapp3.1
netCoreSdkVersion: 3.1.x
system.debug: true
pr:
autoCancel: true
trigger:
batch: true
stages:
- stage: BuildJackett
displayName: Create Binaries
jobs:
- job: Build
workspace:
clean: all
strategy:
matrix:
Mono:
buildDescription: Mono
imageName: ubuntu-latest
framework: net461
runtime: linux-x64
archiveType: tar
artifactName: Jackett.Binaries.Mono.tar.gz
Windows:
buildDescription: Windows
imageName: windows-latest
framework: $(netCoreFramework)
runtime: win-x86
archiveType: zip
artifactName: Jackett.Binaries.Windows.zip
macOS:
buildDescription: macOS
imageName: macOS-latest
framework: $(netCoreFramework)
runtime: osx-x64
archiveType: tar
artifactName: Jackett.Binaries.macOS.tar.gz
LinuxAmdx64:
buildDescription: Linux AMD x64
imageName: ubuntu-latest
framework: $(netCoreFramework)
runtime: linux-x64
archiveType: tar
artifactName: Jackett.Binaries.LinuxAMDx64.tar.gz
LinuxARM32:
buildDescription: Linux ARM32
imageName: ubuntu-latest
framework: $(netCoreFramework)
runtime: linux-arm
archiveType: tar
artifactName: Jackett.Binaries.LinuxARM32.tar.gz
LinuxARM64:
buildDescription: Linux ARM64
imageName: ubuntu-latest
framework: $(netCoreFramework)
runtime: linux-arm64
archiveType: tar
artifactName: Jackett.Binaries.LinuxARM64.tar.gz
pool:
vmImage: $(imageName)
displayName: ${{ variables.buildDescription }}
steps:
- checkout: self
- task: UseDotNet@2
displayName: Install .NET Core SDK
inputs:
packageType: sdk
version: $(netCoreSdkVersion)
installationPath: $(Agent.ToolsDirectory)/dotnet
- task: DotNetCoreCLI@2
displayName: Build Jackett Server
inputs:
command: publish
projects: 'src/Jackett.Server/Jackett.Server.csproj'
publishWebProjects: false
zipAfterPublish: false
arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework) --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)'
- task: DotNetCoreCLI@2
displayName: Build Jackett Updater
inputs:
command: publish
projects: 'src/Jackett.Updater/Jackett.Updater.csproj'
publishWebProjects: false
zipAfterPublish: false
arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework) --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)'
- task: DotNetCoreCLI@2
displayName: Build Jackett Tray (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
command: publish
projects: 'src/Jackett.Tray/Jackett.Tray.csproj'
publishWebProjects: false
zipAfterPublish: false
arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework) --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)'
- task: DotNetCoreCLI@2
displayName: Build Jackett Service (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
command: publish
projects: 'src/Jackett.Service/Jackett.Service.csproj'
publishWebProjects: false
zipAfterPublish: false
arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework) --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)'
- task: CopyFiles@2
displayName: Copy Jackett Server
inputs:
SourceFolder: $(Build.BinariesDirectory)/Jackett.Server
contents: '**'
targetFolder: $(Build.BinariesDirectory)/Jackett
- task: CopyFiles@2
displayName: Copy Jackett Updater
inputs:
SourceFolder: $(Build.BinariesDirectory)/Jackett.Updater
contents: JackettUpdater*
targetFolder: $(Build.BinariesDirectory)/Jackett
- task: CopyFiles@2
displayName: Copy Jackett Tray (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
SourceFolder: $(Build.BinariesDirectory)/Jackett.Tray
contents: |
System.Drawing.dll
System.Security.Cryptography.ProtectedData.dll
WindowsBase.dll
targetFolder: $(Build.BinariesDirectory)/Jackett
overWrite: true
- task: CopyFiles@2
displayName: Copy Jackett Tray Part 2 (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
SourceFolder: $(Build.BinariesDirectory)/Jackett.Tray
contents: '*'
targetFolder: $(Build.BinariesDirectory)/Jackett
overWrite: false
- task: CopyFiles@2
displayName: Copy Jackett Service (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
SourceFolder: $(Build.BinariesDirectory)/Jackett.Service
contents: JackettService*
targetFolder: $(Build.BinariesDirectory)/Jackett
- task: CopyFiles@2
displayName: Copy Mono Specific Scripts
condition: and(succeeded(), startsWith(variables['buildDescription'], 'Mono'))
inputs:
SourceFolder: $(Build.SourcesDirectory)
contents: |
install_service_systemd_mono.sh
Upstart.config
targetFolder: $(Build.BinariesDirectory)/Jackett
- task: CopyFiles@2
displayName: Copy macOS Specific Scripts
condition: and(succeeded(), startsWith(variables['buildDescription'], 'macOS'))
inputs:
SourceFolder: $(Build.SourcesDirectory)
contents: install_service_macos
targetFolder: $(Build.BinariesDirectory)/Jackett
- task: CopyFiles@2
displayName: Copy Linux Specific Scripts
condition: and(succeeded(), startsWith(variables['buildDescription'], 'Linux'))
inputs:
SourceFolder: $(Build.SourcesDirectory)
contents: |
install_service_systemd.sh
jackett_launcher.sh
targetFolder: $(Build.BinariesDirectory)/Jackett
#There is an issue with Mono 5.8 (fixed in Mono 5.12) where its expecting to use its own patched version of System.Net.Http.dll, instead of the version supplied in folder
#https://github.com/dotnet/corefx/issues/19914
#https://bugzilla.xamarin.com/show_bug.cgi?id=60315
#The workaround is to delete System.Net.Http.dll and patch the .exe.config file
#Mono on FreeBSD doesn't like the bundled System.Runtime.InteropServices.RuntimeInformation -> Delete it
#https://github.com/dotnet/corefx/issues/23989
#https://github.com/Jackett/Jackett/issues/3547
- task: PowerShell@2
displayName: Patch Mono Build (Mono only)
condition: and(succeeded(), startsWith(variables['buildDescription'], 'Mono'))
inputs:
workingDirectory: $(Build.BinariesDirectory)/Jackett
targetType: inline
script: |
$file = '$(Build.BinariesDirectory)/Jackett/JackettConsole.exe.config'
$xml = [xml] (Get-Content $file)
$newVersion = $xml.SelectSingleNode("configuration/runtime/*[name()='assemblyBinding']/*[name()='dependentAssembly']/*[name()='assemblyIdentity'][@name='System.Net.Http']/../*[name()='bindingRedirect']/@newVersion")
$newVersion.Value = '4.0.0.0'
$xml.Save($file)
Remove-Item '$(Build.BinariesDirectory)/Jackett/System.Net.Http.dll'
Remove-Item '$(Build.BinariesDirectory)/Jackett/System.Runtime.InteropServices.RuntimeInformation.dll'
- task: Bash@3
displayName: Set Folder and File Permissions (Mono, Linux and macOS)
condition: and(succeeded(), not(startsWith(variables['runtime'], 'win')))
inputs:
workingDirectory: $(Build.BinariesDirectory)/Jackett
targetType: inline
script: |
chmod 755 $(find "$(Build.BinariesDirectory)"/Jackett -type d)
chmod 644 $(find "$(Build.BinariesDirectory)"/Jackett -type f)
chmod 755 jackett
chmod 755 JackettUpdater
if [ -f install_service_systemd_mono.sh ]; then chmod 755 install_service_systemd_mono.sh; fi
if [ -f install_service_macos ]; then chmod 755 install_service_macos; fi
if [ -f install_service_systemd.sh ]; then chmod 755 install_service_systemd.sh; fi
if [ -f jackett_launcher.sh ]; then chmod 755 jackett_launcher.sh; fi
- task: ArchiveFiles@2
displayName: Compress Binaries
inputs:
rootFolderOrFile: $(Build.BinariesDirectory)/Jackett
includeRootFolder: true
archiveType: '$(archiveType)'
tarCompression: gz
archiveFile: '$(Build.ArtifactStagingDirectory)/$(artifactName)'
- task: CmdLine@2
displayName: Create Jackett Installer (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
script: >
iscc.exe $(Build.SourcesDirectory)/Installer.iss
/O"$(Build.ArtifactStagingDirectory)"
/DMyFileForVersion=$(Build.BinariesDirectory)/Jackett/Jackett.Common.dll
/DMySourceFolder=$(Build.BinariesDirectory)/Jackett
/DMyOutputFilename=Jackett.Installer.Windows
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
- task: DotNetCoreCLI@2
displayName: Unit Tests (Windows only)
condition: and(succeeded(), startsWith(variables['runtime'], 'win'))
inputs:
command: test
projects: '**/*.Test*/*.csproj'
arguments: '--configuration $(buildConfiguration) --framework $(framework)'
- task: DotNetCoreCLI@2
displayName: Unit Tests (Mono, Linux and macOS)
condition: and(succeeded(), not(startsWith(variables['runtime'], 'win')))
inputs:
command: test
projects: '**/*.Test*/*.csproj'
arguments: '--configuration $(buildConfiguration) --framework $(framework) --runtime $(runtime)'
- stage: Integration
displayName: Integration Tests
dependsOn: BuildJackett
jobs:
- job: Selenium
workspace:
clean: all
strategy:
matrix:
Mono:
buildDescription: Mono
imageName: ubuntu-latest
artifactName: Jackett.Binaries.Mono.tar.gz
Windows:
buildDescription: Windows
imageName: windows-latest
artifactName: Jackett.Binaries.Windows.zip
# Enable once ChromeDriver is deployed to macOS image https://github.com/actions/virtual-environments/issues/7
# macOS:
# buildDescription: macOS
# imageName: macOS-latest
# artifactName: Jackett.Binaries.macOS.tar.gz
LinuxAmdx64:
buildDescription: Linux AMD x64
imageName: ubuntu-latest
artifactName: Jackett.Binaries.LinuxAMDx64.tar.gz
pool:
vmImage: $(imageName)
displayName: ${{ variables.buildDescription }}
steps:
- checkout: self
- task: DownloadPipelineArtifact@2
displayName: Download artifacts for integration tests
inputs:
patterns: '**/Jackett*'
path: $(Build.ArtifactStagingDirectory)
- task: PowerShell@2
displayName: Install Jackett (Windows only)
condition: and(succeeded(), eq(variables['buildDescription'], 'Windows'))
inputs:
workingDirectory: $(Build.ArtifactStagingDirectory)/drop
targetType: inline
script: |
Start-Process ./Jackett.Installer.Windows.exe /silent -NoNewWindow -Wait
- task: Bash@3
displayName: Install Jackett (Mono, Linux and macOS)
condition: and(succeeded(), ne(variables['buildDescription'], 'Windows'))
inputs:
workingDirectory: $(Build.ArtifactStagingDirectory)/drop
targetType: inline
script: |
tar xzf "$(artifactName)"
cd Jackett
if [[ "$(artifactName)" == *"Mono"* ]]; then mono --version; fi
if [[ "$(artifactName)" == *"Mono"* ]]; then sudo ./install_service_systemd_mono.sh; fi
if [[ "$(artifactName)" == *"macOS"* ]]; then sudo ./install_service_macos; fi
if [[ "$(artifactName)" == *"LinuxAMDx64"* ]]; then sudo ./install_service_systemd.sh; fi
- task: UseDotNet@2
displayName: Install .NET Core SDK
inputs:
packageType: sdk
version: $(netCoreSdkVersion)
installationPath: $(Agent.ToolsDirectory)/dotnet
- task: DotNetCoreCLI@2
displayName: Run Integration Tests
inputs:
command: test
projects: '**/*IntegrationTest*/*.csproj'
- stage: PublishGithub
displayName: Publish to Github
dependsOn: Integration
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
jobs:
- job: Publish
workspace:
clean: all
steps:
- checkout: self
- task: DownloadPipelineArtifact@2
displayName: Download Artifacts for Publish
inputs:
patterns: '**/Jackett*'
path: $(Build.ArtifactStagingDirectory)
- task: GitHubRelease@1
displayName: Create Github release
inputs:
gitHubConnection: github.com_jackett
repositoryName: '$(Build.Repository.Name)'
action: create
target: $(Build.SourceVersion)
tagSource: userSpecifiedTag
tag: v$(Build.BuildNumber)
title: v$(Build.BuildNumber)
assets: $(Build.ArtifactStagingDirectory)/drop/*
assetUploadMode: replace
isDraft: true
addChangeLog: true
compareWith: lastNonDraftRelease
- task: PowerShell@2
displayName: Ensure all artifacts are uploaded to Github
inputs:
targetType: inline
script: |
$json = Invoke-WebRequest 'https://dev.azure.com/jackett/jackett/_apis/build/builds/$(Build.BuildId)/logs?api-version=5.0' | ConvertFrom-Json
$lastTwoLogUrls = $json.value[-1..-2].url
foreach($logUrl in $lastTwoLogUrls)
{
Write-Output $logUrl
$logText = Invoke-WebRequest $logUrl
if ($logText -like '*Creating a release for tag:*')
{
$logInspect = ($logText -split "Creating a release for tag:")[-1]
$successCount = (Select-String "Uploaded file successfully:" -InputObject $logInspect -AllMatches).Matches.Count
$failureCount = (Select-String "Duplicate asset found:" -InputObject $logInspect -AllMatches).Matches.Count
Write-Output "Success count is: $successCount and failure count is: $failureCount"
if (($successCount -ne 7) -or ($failureCount -ne 0)) { Write-Host "##vso[task.complete result=Failed;]DONE" }
}
}

View File

@@ -1,70 +0,0 @@
#!/bin/bash
#Setting up colors
BOLDRED="$(printf '\033[1;31m')"
BOLDGREEN="$(printf '\033[1;32m')"
NC="$(printf '\033[0m')" # No Color
# Stop and unload the service if it's running
launchctl remove org.user.Jackett
# Move working directory to Jackett's
cd "$(dirname "$0")"
# Check if we're running from Jackett's directory
if [ ! -f ./jackett ]; then
echo "${BOLDRED}ERROR${NC}: Couldn't locate ./jackett - Is the script in the right directory?"
exit 1
fi
jackettdir="$(pwd)"
# Check that no other service called Jackett is already running
if [[ $(launchctl list | grep org.user.Jackett) ]]; then
echo "${BOLDRED}ERROR${NC}: Jackett already seems to be running as a service. Please stop it before running this script again."
exit 1
fi
# Write the plist to LaunchAgents
mkdir -p ~/Library/LaunchAgents/
cat >~/Library/LaunchAgents/org.user.Jackett.plist <<EOL
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.user.Jackett</string>
<key>ProgramArguments</key>
<array>
<string>${jackettdir}/jackett</string>
<string>--NoRestart</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>${jackettdir}</string>
</dict>
</plist>
EOL
# Run the agent
launchctl load ~/Library/LaunchAgents/org.user.Jackett.plist
# Check that it's running
if [[ $(launchctl list | grep org.user.Jackett) ]]; then
echo "${BOLDGREEN}Agent successfully installed and launched!${NC}"
else
cat << EOL
${BOLDRED}ERROR${NC}: Could not launch agent. The installation might have failed.
Please open an issue on https://github.com/Jackett/Jackett/issues and paste following information:
Jackett directory: \`${jackettdir}\`
EOL
fi

View File

@@ -1,108 +0,0 @@
#!/bin/bash
# If you have problems installing Jackett, please open an issue on
# https://github.com/Jackett/Jackett/issues
# Setting up colors
BOLDRED="$(printf '\033[1;31m')"
BOLDGREEN="$(printf '\033[1;32m')"
NC="$(printf '\033[0m')" # No Color
# Check if the install script is running as root
if [ "$EUID" -ne 0 ]; then
echo "${BOLDRED}ERROR${NC}: Please run this script as root"
exit 1
fi
# Check if Jackett service is running
JACKETT_SERVICE="jackett.service"
echo "Checking if the service '${JACKETT_SERVICE}' is running ..."
if systemctl is-active --quiet "${JACKETT_SERVICE}"; then
echo "Service '${JACKETT_SERVICE}' is running"
# Stop and unload the service
if systemctl stop "${JACKETT_SERVICE}"; then
echo "Service '${JACKETT_SERVICE}' stopped"
else
echo "${BOLDRED}ERROR${NC}: The service '${JACKETT_SERVICE}' Can not be stopped"
exit 1
fi
else
echo "Service '${JACKETT_SERVICE}' is not running"
fi
# Move working directory to Jackett's
JACKETT_DIR="$(dirname "$(readlink -f "$0")")"
echo "Jackett will be installed in '${JACKETT_DIR}'"
if ! cd "${JACKETT_DIR}"; then
echo "${BOLDRED}ERROR${NC}: Can not cd into '${JACKETT_DIR}' folder"
exit 1
fi
# Check if we're running from Jackett's directory
if [ ! -f ./jackett ]; then
echo "${BOLDRED}ERROR${NC}: Can not locate 'jackett' file in '${JACKETT_DIR}'."
echo "Is the script in the right directory?"
exit 1
fi
# Check if Jackett's owner is root
JACKETT_USER="$(stat -c "%U" ./jackett)"
if [ "${JACKETT_USER}" == "root" ] || [ "${JACKETT_USER}" == "UNKNOWN" ] ; then
echo "${BOLDRED}ERROR${NC}: The owner of Jackett directory is '${JACKETT_USER}'."
echo "Please, change the owner with the command 'chown <user>:<user> -R \"${JACKETT_DIR}\"'"
echo "The user <user> will be used to run Jackett."
exit 1
fi
echo "Jackett will be executed with the user '${JACKETT_USER}'"
# Write the systemd service descriptor
JACKETT_SERVICE_PATH="/etc/systemd/system/${JACKETT_SERVICE}"
echo "Creating Jackett unit file in '${JACKETT_SERVICE_PATH}' ..."
cat > "${JACKETT_SERVICE_PATH}" <<EOL
[Unit]
Description=Jackett Daemon
After=network.target
[Service]
SyslogIdentifier=jackett
Restart=always
RestartSec=5
Type=simple
User=${JACKETT_USER}
Group=${JACKETT_USER}
WorkingDirectory=${JACKETT_DIR}
ExecStart=/bin/sh "${JACKETT_DIR}/jackett_launcher.sh"
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
EOL
if [ $? -ne 0 ]; then
echo "${BOLDRED}ERROR${NC}: Can not create the file '${JACKETT_SERVICE_PATH}'"
echo "The UnitPath of systemd changes from one distribution to another. You may have to edit the script and change the path manually."
exit 1
fi
echo "Installing Jackett service ..."
# Reload systemd daemon
if ! systemctl daemon-reload; then
echo "${BOLDRED}ERROR${NC}: Can not reload systemd daemon"
exit 1
fi
# Enable the service for following restarts
if ! systemctl enable "${JACKETT_SERVICE}"; then
echo "${BOLDRED}ERROR${NC}: Can not enable the service '${JACKETT_SERVICE}'"
exit 1
fi
# Run the service
if systemctl start "${JACKETT_SERVICE}"; then
echo "${BOLDGREEN}Service successfully installed and launched!${NC}"
else
echo "${BOLDRED}ERROR${NC}: Can not start the service '${JACKETT_SERVICE}'"
exit 1
fi

View File

@@ -1,117 +0,0 @@
#!/bin/bash
# If you have problems installing Jackett, please open an issue on
# https://github.com/Jackett/Jackett/issues
# Setting up colors
BOLDRED="$(printf '\033[1;31m')"
BOLDGREEN="$(printf '\033[1;32m')"
NC="$(printf '\033[0m')" # No Color
# Check if the install script is running as root
if [ "$EUID" -ne 0 ]; then
echo "${BOLDRED}ERROR${NC}: Please run this script as root"
exit 1
fi
# Check if Jackett service is running
JACKETT_SERVICE="jackett.service"
echo "Checking if the service '${JACKETT_SERVICE}' is running ..."
if systemctl is-active --quiet "${JACKETT_SERVICE}"; then
echo "Service '${JACKETT_SERVICE}' is running"
# Stop and unload the service
if systemctl stop "${JACKETT_SERVICE}"; then
echo "Service '${JACKETT_SERVICE}' stopped"
else
echo "${BOLDRED}ERROR${NC}: The service '${JACKETT_SERVICE}' Can not be stopped"
exit 1
fi
else
echo "Service '${JACKETT_SERVICE}' is not running"
fi
# Move working directory to Jackett's
JACKETT_DIR="$(dirname "$(readlink -f "$0")")"
echo "Jackett will be installed in '${JACKETT_DIR}'"
if ! cd "${JACKETT_DIR}"; then
echo "${BOLDRED}ERROR${NC}: Can not cd into '${JACKETT_DIR}' folder"
exit 1
fi
# Check if we're running from Jackett's directory
if [ ! -f ./JackettConsole.exe ]; then
echo "${BOLDRED}ERROR${NC}: Can not locate 'JackettConsole.exe' file in '${JACKETT_DIR}'."
echo "Is the script in the right directory?"
exit 1
fi
# Check if Jackett's owner is root
JACKETT_USER="$(stat -c "%U" ./JackettConsole.exe)"
if [ "${JACKETT_USER}" == "root" ] || [ "${JACKETT_USER}" == "UNKNOWN" ] ; then
echo "${BOLDRED}ERROR${NC}: The owner of Jackett directory is '${JACKETT_USER}'."
echo "Please, change the owner with the command 'chown <user>:<user> -R \"${JACKETT_DIR}\"'"
echo "The user <user> will be used to run Jackett."
exit 1
fi
echo "Jackett will be executed with the user '${JACKETT_USER}'"
# Check if Mono is installed
echo "Checking if Mono is installed ..."
if ! command -v mono > /dev/null; then
echo "${BOLDRED}ERROR${NC}: Jackett requires Mono but it's not installed"
exit 1
fi
MONO_DIR="$(dirname "$(command -v mono)")"
echo "Mono is installed in '${MONO_DIR}'"
# Write the systemd service descriptor
JACKETT_SERVICE_PATH="/etc/systemd/system/${JACKETT_SERVICE}"
echo "Creating Jackett unit file in '${JACKETT_SERVICE_PATH}' ..."
cat > "${JACKETT_SERVICE_PATH}" <<EOL
[Unit]
Description=Jackett Daemon
After=network.target
[Service]
SyslogIdentifier=jackett
Restart=always
RestartSec=5
Type=simple
User=${JACKETT_USER}
Group=${JACKETT_USER}
WorkingDirectory=${JACKETT_DIR}
ExecStart="${MONO_DIR}/mono" --debug "${JACKETT_DIR}/JackettConsole.exe" --NoRestart
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
EOL
if [ $? -ne 0 ]; then
echo "${BOLDRED}ERROR${NC}: Can not create the file '${JACKETT_SERVICE_PATH}'"
echo "The UnitPath of systemd changes from one distribution to another. You may have to edit the script and change the path manually."
exit 1
fi
echo "Installing Jackett service ..."
# Reload systemd daemon
if ! systemctl daemon-reload; then
echo "${BOLDRED}ERROR${NC}: Can not reload systemd daemon"
exit 1
fi
# Enable the service for following restarts
if ! systemctl enable "${JACKETT_SERVICE}"; then
echo "${BOLDRED}ERROR${NC}: Can not enable the service '${JACKETT_SERVICE}'"
exit 1
fi
# Run the service
if systemctl start "${JACKETT_SERVICE}"; then
echo "${BOLDGREEN}Service successfully installed and launched!${NC}"
else
echo "${BOLDRED}ERROR${NC}: Can not start the service '${JACKETT_SERVICE}'"
exit 1
fi

View File

@@ -1,18 +0,0 @@
#!/bin/sh
# Helper script to fix
# https://github.com/Jackett/Jackett/issues/5208#issuecomment-547565515
# Get full Jackett root path
JACKETT_DIR="$(dirname "$(readlink -f "$0")")"
# Launch Jackett
"${JACKETT_DIR}/jackett" --NoRestart
# Get user running the service
JACKETT_USER=$(whoami)
# Wait until the updater ends
while pgrep -u "${JACKETT_USER}" JackettUpdater > /dev/null; do
sleep 1
done

View File

@@ -0,0 +1,239 @@
using System;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// Called when cURL has debug information for the client.
/// </summary>
/// <remarks>
/// For usage, see the sample <c>Upload.cs</c>.
/// Arguments passed to the recipient include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>infoType</term>
/// <description>
/// Type of debug information, see
/// <see cref="CurlInfoType" />.
/// </description>
/// </item>
/// <item>
/// <term>message</term>
/// <description>Debug information as a string.</description>
/// </item>
/// <item>
/// <term>extraData</term>
/// <description>Client-provided extra data.</description>
/// </item>
/// </list>
/// </remarks>
public delegate void CurlDebugCallback(CurlInfoType infoType, String message, Object extraData);
/// <summary>
/// Called when cURL has header data for the client.
/// </summary>
/// <remarks>
/// For usage, see the sample <c>Headers.cs</c>.
/// Arguments passed to the recipient include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>buf</term>
/// <description>Header data from cURL to the client.</description>
/// </item>
/// <item>
/// <term>size</term>
/// <description>Size of a character, in bytes.</description>
/// </item>
/// <item>
/// <term>nmemb</term>
/// <description>Number of characters.</description>
/// </item>
/// <item>
/// <term>extraData</term>
/// <description>Client-provided extra data.</description>
/// </item>
/// </list>
/// Your implementation should return the number of bytes (not
/// characters) processed. Usually this is <c>size * nmemb</c>.
/// Return -1 to abort the transfer.
/// </remarks>
public delegate int CurlHeaderCallback(byte[] buf, int size, int nmemb, Object extraData);
/// <summary>
/// Called when cURL needs for the client to perform an
/// IOCTL operation. An example might be when an FTP
/// upload requires rewinding of the input file to deal
/// with a resend occasioned by an error.
/// </summary>
/// <remarks>
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>cmd</term>
/// <description>
/// A <see cref="CurlIoCommand" />; for now, only
/// <c>RestartRead</c> should be passed.
/// </description>
/// </item>
/// <item>
/// <term>extraData</term>
/// <description>
/// Client-provided extra data; in the
/// case of an FTP upload, it might be a
/// <c>FileStream</c> object.
/// </description>
/// </item>
/// </list>
/// Your implementation should return a <see cref="CurlIoError" />,
/// which should be <see cref="CurlIoError.Ok" /> if everything
/// is okay.
/// </remarks>
public delegate CurlIoError CurlIoctlCallback(CurlIoCommand cmd, Object extraData);
/// <summary>
/// Called when cURL wants to report progress.
/// </summary>
/// <remarks>
/// For usage, see the sample <c>Upload.cs</c>.
/// Arguments passed to the recipient include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>extraData</term>
/// <description>Client-provided extra data.</description>
/// </item>
/// <item>
/// <term>dlTotal</term>
/// <description>Number of bytes to download.</description>
/// </item>
/// <item>
/// <term>dlNow</term>
/// <description>Number of bytes downloaded so far.</description>
/// </item>
/// <item>
/// <term>ulTotal</term>
/// <description>Number of bytes to upload.</description>
/// </item>
/// <item>
/// <term>ulNow</term>
/// <description>Number of bytes uploaded so far.</description>
/// </item>
/// </list>
/// Your implementation should return 0 to continue, or a non-zero
/// value to abort the transfer.
/// </remarks>
public delegate int CurlProgressCallback(Object extraData, double dlTotal, double dlNow,
double ulTotal, double ulNow);
/// <summary>
/// Called when cURL wants to read data from the client.
/// </summary>
/// <remarks>
/// For usage, see the sample <c>Upload.cs</c>.
/// Arguments passed to the recipient include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>buf</term>
/// <description>
/// Buffer into which your client should write data
/// for cURL.
/// </description>
/// </item>
/// <item>
/// <term>size</term>
/// <description>Size of a character, usually 1.</description>
/// </item>
/// <item>
/// <term>nmemb</term>
/// <description>Number of characters.</description>
/// </item>
/// <item>
/// <term>extraData</term>
/// <description>Client-provided extra data.</description>
/// </item>
/// </list>
/// Your implementation should return the number of bytes (not
/// characters) written to <c>buf</c>. Return 0 to abort the transfer.
/// </remarks>
public delegate int CurlReadCallback([Out] byte[] buf, int size, int nmemb, Object extraData);
/// <summary>
/// Called when cURL wants to report an Ssl event.
/// </summary>
/// <remarks>
/// For usage, see the sample <c>SSLGet.cs</c>.
/// Arguments passed to the recipient include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>ctx</term>
/// <description>
/// An <see cref="CurlSslContext" /> object that wraps an
/// OpenSSL <c>SSL_CTX</c> pointer.
/// </description>
/// </item>
/// <item>
/// <term>extraData</term>
/// <description>Client-provided extra data.</description>
/// </item>
/// </list>
/// Your implementation should return a <see cref="CurlCode" />,
/// which should be <see cref="CurlCode.Ok" /> if everything
/// is okay.
/// </remarks>
public delegate CurlCode CurlSslContextCallback(CurlSslContext ctx, Object extraData);
/// <summary>
/// Called when cURL has data for the client.
/// </summary>
/// <remarks>
/// For usage, see the example <c>EasyGet.cs</c>.
/// Arguments passed to the delegate implementation include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term>buf</term>
/// <description>Data cURL is providing to the client.</description>
/// </item>
/// <item>
/// <term>size</term>
/// <description>Size of a character, usually 1.</description>
/// </item>
/// <item>
/// <term>nmemb</term>
/// <description>Number of characters.</description>
/// </item>
/// <item>
/// <term>extraData</term>
/// <description>Client-provided extra data.</description>
/// </item>
/// </list>
/// Your implementation should return the number of bytes (not
/// characters) processed. Return 0 to abort the transfer.
/// </remarks>
public delegate int CurlWriteCallback(byte[] buf, int size, int nmemb, Object extraData);
}

View File

@@ -0,0 +1,75 @@
using System;
namespace CurlSharp
{
/// <summary>
/// Called when <c>cURL</c> wants to lock a shared resource.
/// </summary>
/// <remarks>
/// For a usage example, refer to the <c>ShareDemo.cs</c> sample.
/// Arguments passed to your delegate implementation include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>data</term>
/// <term>
/// Type of data to lock; one of the values in the
/// <see cref="CurlLockData" /> enumeration.
/// </term>
/// </item>
/// <item>
/// <term>access</term>
/// <term>
/// Lock access requested; one of the values in the
/// <see cref="CurlLockAccess" /> enumeration.
/// </term>
/// </item>
/// <item>
/// <term>userData</term>
/// <term>
/// Client-provided data that is not touched internally by
/// <c>cURL</c>. This is set via
/// <see cref="CurlShareOption.UserData" /> when calling the
/// <see cref="CurlShare.SetOpt" /> member of the <see cref="CurlShare" />
/// class.
/// </term>
/// </item>
/// </list>
/// </remarks>
public delegate void CurlShareLockCallback(CurlLockData data, CurlLockAccess access, Object userData);
/// <summary>
/// Called when <c>cURL</c> wants to unlock a shared resource.
/// </summary>
/// <remarks>
/// For a usage example, refer to the <c>ShareDemo.cs</c> sample.
/// Arguments passed to your delegate implementation include:
/// <list type="table">
/// <listheader>
/// <term>Argument</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>data</term>
/// <term>
/// Type of data to unlock; one of the values in the
/// <see cref="CurlLockData" /> enumeration.
/// </term>
/// </item>
/// <item>
/// <term>userData</term>
/// <term>
/// Client-provided data that is not touched internally by
/// <c>cURL</c>. This is set via
/// <see cref="CurlShareOption.UserData" /> when calling the
/// <see cref="CurlShare.SetOpt" /> member of the <see cref="CurlShare" />
/// class.
/// </term>
/// </item>
/// </list>
/// </remarks>
public delegate void CurlShareUnlockCallback(CurlLockData data, Object userData);
}

170
src/CurlSharp/Curl.cs Normal file
View File

@@ -0,0 +1,170 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// Top-level class for initialization and cleanup.
/// </summary>
/// <remarks>
/// It also implements static methods for capabilities that don't
/// logically belong in a class.
/// </remarks>
public static class Curl
{
// for state management
private static CurlCode _initCode;
/// <summary>
/// Class constructor - initialize global status.
/// </summary>
static Curl()
{
_initCode = CurlCode.FailedInit;
}
// hidden instance stuff
/// <summary>
/// Get the underlying cURL version as a string, example "7.12.2".
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// Thrown if cURL isn't properly initialized.
/// </exception>
public static string Version
{
get
{
EnsureCurl();
return Marshal.PtrToStringAnsi(NativeMethods.curl_version());
}
}
/// <summary>
/// Process-wide initialization -- call only once per process.
/// </summary>
/// <param name="flags">
/// An or'd combination of
/// <see cref="CurlInitFlag" /> members.
/// </param>
/// <returns>
/// A <see cref="CurlCode" />, hopefully
/// <c>CurlCode.Ok</c>.
/// </returns>
public static CurlCode GlobalInit(CurlInitFlag flags)
{
_initCode = NativeMethods.curl_global_init((int)flags);
#if USE_LIBCURLSHIM
if (_initCode == CurlCode.Ok)
NativeMethods.curl_shim_initialize();
#endif
return _initCode;
}
/// <summary>
/// Process-wide cleanup -- call just before exiting process.
/// </summary>
/// <remarks>
/// While it's not necessary that your program call this method
/// before exiting, doing so will prevent leaks of native cURL resources.
/// </remarks>
public static void GlobalCleanup()
{
if (_initCode == CurlCode.Ok)
{
#if USE_LIBCURLSHIM
NativeMethods.curl_shim_cleanup();
#endif
NativeMethods.curl_global_cleanup();
_initCode = CurlCode.FailedInit;
}
}
/// <summary>
/// URL encode a String.
/// </summary>
/// <param name="url">The string to URL encode.</param>
/// <param name="length">
/// Input string length;
/// use 0 for cURL to determine.
/// </param>
/// <returns>A new URL encoded string.</returns>
/// <exception cref="System.InvalidOperationException">
/// Thrown if cURL isn't properly initialized.
/// </exception>
public static string Escape(string url, int length)
{
EnsureCurl();
var p = NativeMethods.curl_escape(url, length);
var s = Marshal.PtrToStringAnsi(p);
NativeMethods.curl_free(p);
return s;
}
/// <summary>
/// URL decode a String.
/// </summary>
/// <param name="url">The string to URL decode.</param>
/// <param name="length">
/// Input string length;
/// use 0 for cURL to determine.
/// </param>
/// <returns>A new URL decoded string.</returns>
/// <exception cref="System.InvalidOperationException">
/// Thrown if cURL isn't properly initialized.
/// </exception>
public static string Unescape(string url, int length)
{
EnsureCurl();
var p = NativeMethods.curl_unescape(url, length);
var s = Marshal.PtrToStringAnsi(p);
NativeMethods.curl_free(p);
return s;
}
/// <summary>
/// Get a <see cref="CurlVersionInfoData" /> object.
/// </summary>
/// <param name="ver">
/// Specify a <see cref="CurlVersion" />, such as
/// <c>CurlVersion.Now</c>.
/// </param>
/// <returns>A <see cref="CurlVersionInfoData" /> object.</returns>
/// <exception cref="System.InvalidOperationException">
/// Thrown if cURL isn't properly initialized.
/// </exception>
public static CurlVersionInfoData GetVersionInfo(CurlVersion ver)
{
EnsureCurl();
return new CurlVersionInfoData(ver);
}
/// <summary>
/// Called by other classes to ensure valid cURL state.
/// </summary>
internal static void EnsureCurl()
{
if (_initCode != CurlCode.Ok)
throw new InvalidOperationException("cURL not initialized");
}
}
}

2161
src/CurlSharp/CurlEasy.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,388 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// This trivial class wraps the internal <c>curl_forms</c> struct.
/// </summary>
public sealed class CurlForms
{
/// <summary>The <see cref="CurlFormOption" />.</summary>
public CurlFormOption Option;
/// <summary>Value for the option.</summary>
public Object Value;
}
/// <summary>
/// Wraps a section of multipart form data to be submitted via the
/// <see cref="CurlOption.HttpPost" /> option in the
/// <see cref="CurlEasy.SetOpt" /> member of the <see cref="CurlEasy" /> class.
/// </summary>
public class CurlHttpMultiPartForm : IDisposable
{
// the two curlform pointers
private readonly IntPtr[] _pItems;
/// <summary>
/// Constructor
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// This is thrown
/// if <see cref="Curl" /> hasn't bee properly initialized.
/// </exception>
public CurlHttpMultiPartForm()
{
Curl.EnsureCurl();
_pItems = new IntPtr[2];
_pItems[0] = IntPtr.Zero;
_pItems[1] = IntPtr.Zero;
}
/// <summary>
/// Free unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Destructor
/// </summary>
~CurlHttpMultiPartForm()
{
Dispose(false);
}
// for CurlEasy.SetOpt()
internal IntPtr GetHandle()
{
return _pItems[0];
}
/// <summary>
/// Add a multi-part form section.
/// </summary>
/// <param name="args">
/// Argument list, as described in the remarks.
/// </param>
/// <returns>
/// A <see cref="CurlFormCode" />, hopefully
/// <c>CurlFormCode.Ok</c>.
/// </returns>
/// <remarks>
/// This is definitely the workhorse method for this class. It
/// should be called in roughly the same manner as
/// <c>curl_formadd()</c>, except you would omit the first two
/// <c>struct curl_httppost**</c> arguments (<c>firstitem</c> and
/// <c>lastitem</c>), which are wrapped in this class. So you should
/// pass arguments in the following sequence:
/// <para>
/// <c>
/// CurlHttpMultiPartForm.AddSection(option1, value1, ..., optionX, valueX,
/// CurlFormOption.End)
/// </c>
/// ;
/// </para>
/// <para>
/// For a complete list of possible options, see the documentation for
/// the <see cref="CurlFormOption" /> enumeration.
/// </para>
/// <note>
/// The pointer options (<c>PtrName</c>, etc.) make an
/// internal copy of the passed <c>byte</c> array. Therefore, any
/// changes you make to the client copy of this array AFTER calling
/// this method, won't be reflected internally with <c>cURL</c>. The
/// purpose of providing the pointer options is to support the
/// posting of non-string binary data.
/// </note>
/// </remarks>
public CurlFormCode AddSection(params object[] args)
{
var nCount = args.Length;
var nRealCount = nCount;
var retCode = CurlFormCode.Ok;
CurlForms[] aForms = null;
// one arg or even number of args is an error
if ((nCount == 1) || (nCount%2 == 0))
return CurlFormCode.Incomplete;
// ensure the last argument is End
var iCode = (CurlFormOption)
Convert.ToInt32(args.GetValue(nCount - 1));
if (iCode != CurlFormOption.End)
return CurlFormCode.Incomplete;
// walk through any passed arrays to get the true number of
// items and ensure the child arrays are properly (and not
// prematurely) terminated with End
for (var i = 0; i < nCount; i += 2)
{
iCode = (CurlFormOption) Convert.ToInt32(args.GetValue(i));
switch (iCode)
{
case CurlFormOption.Array:
{
aForms = args.GetValue(i + 1) as CurlForms[];
if (aForms == null)
return CurlFormCode.Incomplete;
var nFormsCount = aForms.Length;
for (var j = 0; j < nFormsCount; j++)
{
var pcf = aForms.GetValue(j) as CurlForms;
if (pcf == null)
return CurlFormCode.Incomplete;
if (j == nFormsCount - 1)
{
if (pcf.Option != CurlFormOption.End)
return CurlFormCode.Incomplete;
}
else
{
if (pcf.Option == CurlFormOption.End)
return CurlFormCode.Incomplete;
}
}
// -2 accounts for the fact that we're a) not
// including the item with End and b) not
// including Array in what we pass to cURL
nRealCount += 2*(nFormsCount - 2);
break;
}
}
}
// allocate the IntPtr array for the data
var aPointers = new IntPtr[nRealCount];
for (var i = 0; i < nRealCount - 1; i++)
aPointers[i] = IntPtr.Zero;
aPointers[nRealCount - 1] = (IntPtr) CurlFormOption.End;
// now we go through the args
aForms = null;
var formArrayPos = 0;
var argArrayPos = 0;
var ptrArrayPos = 0;
Object obj = null;
while ((retCode == CurlFormCode.Ok) &&
(ptrArrayPos < nRealCount))
{
if (aForms != null)
{
var pcf = aForms.GetValue(formArrayPos++)
as CurlForms;
if (pcf == null)
{
retCode = CurlFormCode.UnknownOption;
break;
}
iCode = pcf.Option;
obj = pcf.Value;
}
else
{
iCode = (CurlFormOption) Convert.ToInt32(
args.GetValue(argArrayPos++));
obj = (iCode == CurlFormOption.End)
? null
: args.GetValue(argArrayPos++);
}
switch (iCode)
{
// handle byte-array pointer-related items
case CurlFormOption.PtrName:
case CurlFormOption.PtrContents:
case CurlFormOption.BufferPtr:
{
var bytes = obj as byte[];
if (bytes == null)
retCode = CurlFormCode.UnknownOption;
else
{
var nLen = bytes.Length;
var ptr = Marshal.AllocHGlobal(nLen);
if (ptr != IntPtr.Zero)
{
aPointers[ptrArrayPos++] = (IntPtr) iCode;
// copy bytes to unmanaged buffer
for (var j = 0; j < nLen; j++)
Marshal.WriteByte(ptr, bytes[j]);
aPointers[ptrArrayPos++] = ptr;
}
else
retCode = CurlFormCode.Memory;
}
break;
}
// length values
case CurlFormOption.NameLength:
case CurlFormOption.ContentsLength:
case CurlFormOption.BufferLength:
aPointers[ptrArrayPos++] = (IntPtr) iCode;
aPointers[ptrArrayPos++] = (IntPtr)
Convert.ToInt32(obj);
break;
// strings
case CurlFormOption.CopyName:
case CurlFormOption.CopyContents:
case CurlFormOption.FileContent:
case CurlFormOption.File:
case CurlFormOption.ContentType:
case CurlFormOption.Filename:
case CurlFormOption.Buffer:
{
aPointers[ptrArrayPos++] = (IntPtr) iCode;
var s = obj as String;
if (s == null)
retCode = CurlFormCode.UnknownOption;
else
{
var p = Marshal.StringToHGlobalAnsi(s);
if (p != IntPtr.Zero)
aPointers[ptrArrayPos++] = p;
else
retCode = CurlFormCode.Memory;
}
break;
}
// array case: already handled
case CurlFormOption.Array:
if (aForms != null)
retCode = CurlFormCode.IllegalArray;
else
{
aForms = obj as CurlForms[];
if (aForms == null)
retCode = CurlFormCode.UnknownOption;
}
break;
// slist
case CurlFormOption.ContentHeader:
{
aPointers[ptrArrayPos++] = (IntPtr) iCode;
var s = obj as CurlSlist;
if (s == null)
retCode = CurlFormCode.UnknownOption;
else
aPointers[ptrArrayPos++] = s.Handle;
break;
}
// erroneous stuff
case CurlFormOption.Nothing:
retCode = CurlFormCode.Incomplete;
break;
// end
case CurlFormOption.End:
if (aForms != null) // end of form
{
aForms = null;
formArrayPos = 0;
}
else
aPointers[ptrArrayPos++] = (IntPtr) iCode;
break;
// default is unknown
default:
retCode = CurlFormCode.UnknownOption;
break;
}
}
// ensure we didn't come up short on parameters
if (ptrArrayPos != nRealCount)
retCode = CurlFormCode.Incomplete;
// if we're OK here, call into curl
if (retCode == CurlFormCode.Ok)
{
#if USE_LIBCURLSHIM
retCode = (CurlFormCode) NativeMethods.curl_shim_formadd(_pItems, aPointers, nRealCount);
#else
retCode = (CurlFormCode) NativeMethods.curl_formadd(ref _pItems[0], ref _pItems[1],
(int) aPointers[0], aPointers[1],
(int) aPointers[2], aPointers[3],
(int) aPointers[4]);
#endif
}
// unmarshal native allocations
for (var i = 0; i < nRealCount - 1; i += 2)
{
iCode = (CurlFormOption) (int) aPointers[i];
switch (iCode)
{
case CurlFormOption.CopyName:
case CurlFormOption.CopyContents:
case CurlFormOption.FileContent:
case CurlFormOption.File:
case CurlFormOption.ContentType:
case CurlFormOption.Filename:
case CurlFormOption.Buffer:
// byte buffer cases
case CurlFormOption.PtrName:
case CurlFormOption.PtrContents:
case CurlFormOption.BufferPtr:
{
if (aPointers[i + 1] != IntPtr.Zero)
Marshal.FreeHGlobal(aPointers[i + 1]);
break;
}
default:
break;
}
}
return retCode;
}
private void Dispose(bool disposing)
{
lock (this)
{
if (disposing)
{
// clean up managed objects
}
// clean up native objects
if (_pItems[0] != IntPtr.Zero)
NativeMethods.curl_formfree(_pItems[0]);
_pItems[0] = IntPtr.Zero;
_pItems[1] = IntPtr.Zero;
}
}
}
}

302
src/CurlSharp/CurlMulti.cs Normal file
View File

@@ -0,0 +1,302 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
using System.Collections;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// Implements the <c>curl_multi_xxx</c> API.
/// </summary>
public class CurlMulti : IDisposable
{
// private members
private readonly Hashtable _htEasy;
private int _maxFd;
private CurlMultiInfo[] _multiInfo;
private bool _bGotMultiInfo;
#if USE_LIBCURLSHIM
private IntPtr _fdSets;
#else
private NativeMethods.fd_set _fd_read, _fd_write, _fd_except;
#endif
private IntPtr _pMulti;
/// <summary>
/// Constructor
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// This is thrown
/// if <see cref="Curl" /> hasn't bee properly initialized.
/// </exception>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public CurlMulti()
{
Curl.EnsureCurl();
_pMulti = NativeMethods.curl_multi_init();
ensureHandle();
_maxFd = 0;
#if USE_LIBCURLSHIM
_fdSets = IntPtr.Zero;
_fdSets = NativeMethods.curl_shim_alloc_fd_sets();
#else
_fd_read = NativeMethods.fd_set.Create();
_fd_read = NativeMethods.fd_set.Create();
_fd_write = NativeMethods.fd_set.Create();
_fd_except = NativeMethods.fd_set.Create();
#endif
_multiInfo = null;
_bGotMultiInfo = false;
_htEasy = new Hashtable();
}
/// <summary>
/// Max file descriptor
/// </summary>
public int MaxFd
{
get { return _maxFd; }
}
/// <summary>
/// Cleanup unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Destructor
/// </summary>
~CurlMulti()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
lock (this)
{
// if (disposing) // managed member cleanup
// unmanaged cleanup
if (_pMulti != IntPtr.Zero)
{
NativeMethods.curl_multi_cleanup(_pMulti);
_pMulti = IntPtr.Zero;
}
#if USE_LIBCURLSHIM
if (_fdSets != IntPtr.Zero)
{
NativeMethods.curl_shim_free_fd_sets(_fdSets);
_fdSets = IntPtr.Zero;
}
#else
_fd_read.Cleanup();
_fd_write.Cleanup();
_fd_except.Cleanup();
#endif
}
}
private void ensureHandle()
{
if (_pMulti == IntPtr.Zero)
throw new NullReferenceException("No internal multi handle");
}
/// <summary>
/// Add an CurlEasy object.
/// </summary>
/// <param name="curlEasy">
/// <see cref="CurlEasy" /> object to add.
/// </param>
/// <returns>
/// A <see cref="CurlMultiCode" />, hopefully <c>CurlMultiCode.Ok</c>
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public CurlMultiCode AddHandle(CurlEasy curlEasy)
{
ensureHandle();
var p = curlEasy.Handle;
_htEasy.Add(p, curlEasy);
return NativeMethods.curl_multi_add_handle(_pMulti, p);
}
/// <summary>
/// Remove an CurlEasy object.
/// </summary>
/// <param name="curlEasy">
/// <see cref="CurlEasy" /> object to remove.
/// </param>
/// <returns>
/// A <see cref="CurlMultiCode" />, hopefully <c>CurlMultiCode.Ok</c>
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public CurlMultiCode RemoveHandle(CurlEasy curlEasy)
{
ensureHandle();
var p = curlEasy.Handle;
_htEasy.Remove(p);
return NativeMethods.curl_multi_remove_handle(_pMulti, curlEasy.Handle);
}
/// <summary>
/// Get a string description of an error code.
/// </summary>
/// <param name="errorNum">
/// The <see cref="CurlMultiCode" /> for which to obtain the error
/// string description.
/// </param>
/// <returns>The string description.</returns>
public String StrError(CurlMultiCode errorNum)
{
return Marshal.PtrToStringAnsi(NativeMethods.curl_multi_strerror(errorNum));
}
/// <summary>
/// Read/write data to/from each CurlEasy object.
/// </summary>
/// <param name="runningObjects">
/// The number of <see cref="CurlEasy" /> objects still in process is
/// written by this function to this reference parameter.
/// </param>
/// <returns>
/// A <see cref="CurlMultiCode" />, hopefully <c>CurlMultiCode.Ok</c>
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public CurlMultiCode Perform(ref int runningObjects)
{
ensureHandle();
return NativeMethods.curl_multi_perform(_pMulti, ref runningObjects);
}
/// <summary>
/// Set internal file desriptor information before calling Select.
/// </summary>
/// <returns>
/// A <see cref="CurlMultiCode" />, hopefully <c>CurlMultiCode.Ok</c>
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public CurlMultiCode FdSet()
{
ensureHandle();
#if USE_LIBCURLSHIM
return NativeMethods.curl_shim_multi_fdset(_pMulti, _fdSets, ref _maxFd);
#else
NativeMethods.FD_ZERO(_fd_read);
NativeMethods.FD_ZERO(_fd_write);
NativeMethods.FD_ZERO(_fd_except);
return NativeMethods.curl_multi_fdset(_pMulti, ref _fd_read, ref _fd_write, ref _fd_except, ref _maxFd);
#endif
}
/// <summary>
/// Call <c>select()</c> on the CurlEasy objects.
/// </summary>
/// <param name="timeoutMillis">
/// The timeout for the internal <c>select()</c> call,
/// in milliseconds.
/// </param>
/// <returns>
/// Number or <see cref="CurlEasy" /> objects with pending reads.
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public int Select(int timeoutMillis)
{
ensureHandle();
#if USE_LIBCURLSHIM
return NativeMethods.curl_shim_select(_maxFd + 1, _fdSets, timeoutMillis);
#else
var timeout = NativeMethods.timeval.Create(timeoutMillis);
return NativeMethods.select(_maxFd + 1, ref _fd_read, ref _fd_write, ref _fd_except, ref timeout);
//return NativeMethods.select2(_maxFd + 1, _fd_read, _fd_write, _fd_except, timeout);
#endif
}
/// <summary>
/// Obtain status information for a CurlMulti transfer. Requires
/// CurlSharp be compiled with the libcurlshim helper.
/// </summary>
/// <returns>
/// An array of <see cref="CurlMultiInfo" /> objects, one for each
/// <see cref="CurlEasy" /> object child.
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if the native <c>CurlMulti</c> handle wasn't
/// created successfully.
/// </exception>
public CurlMultiInfo[] InfoRead()
{
if (_bGotMultiInfo)
return _multiInfo;
_bGotMultiInfo = true;
#if USE_LIBCURLSHIM
var nMsgs = 0;
var pInfo = NativeMethods.curl_shim_multi_info_read(_pMulti, ref nMsgs);
if (pInfo != IntPtr.Zero)
{
_multiInfo = new CurlMultiInfo[nMsgs];
for (var i = 0; i < nMsgs; i++)
{
var msg = (CurlMessage) Marshal.ReadInt32(pInfo, i*12);
var pEasy = Marshal.ReadIntPtr(pInfo, i*12 + 4);
var code = (CurlCode) Marshal.ReadInt32(pInfo, i*12 + 8);
_multiInfo[i] = new CurlMultiInfo(msg, (CurlEasy) _htEasy[pEasy], code);
}
NativeMethods.curl_shim_multi_info_free(pInfo);
}
return _multiInfo;
#else
throw new NotImplementedException(
"Sorry, CurlMulti.InfoRead is not implemented on this system."
);
#endif
}
}
}

View File

@@ -0,0 +1,65 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
namespace CurlSharp
{
/// <summary>
/// Wraps the <c>cURL</c> struct <c>CURLMsg</c>. This class provides
/// status information following a <see cref="CurlMulti" /> transfer.
/// </summary>
public sealed class CurlMultiInfo
{
// private members
private readonly CurlEasy _mCurlEasy;
private readonly CurlMessage _msg;
private readonly CurlCode _result;
internal CurlMultiInfo(CurlMessage msg, CurlEasy curlEasy, CurlCode result)
{
_msg = msg;
_mCurlEasy = curlEasy;
_result = result;
}
/// <summary>
/// Get the status code from the <see cref="CurlMessage" /> enumeration.
/// </summary>
public CurlMessage Msg
{
get { return _msg; }
}
/// <summary>
/// Get the <see cref="CurlEasy" /> object for this child.
/// </summary>
public CurlEasy CurlEasyHandle
{
get { return _mCurlEasy; }
}
/// <summary>
/// Get the return code for the transfer, as a
/// <see cref="CurlCode" />.
/// </summary>
public CurlCode Result
{
get { return _result; }
}
}
}

276
src/CurlSharp/CurlShare.cs Normal file
View File

@@ -0,0 +1,276 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// This class provides an infrastructure for serializing access to data
/// shared by multiple <see cref="CurlEasy" /> objects, including cookie data
/// and Dns hosts. It implements the <c>curl_share_xxx</c> API.
/// </summary>
public class CurlShare : IDisposable
{
// private members
private GCHandle _hThis; // for handle extraction
private CurlShareCode _lastErrorCode;
private string _lastErrorDescription;
#if USE_LIBCURLSHIM
private NativeMethods._ShimLockCallback _pDelLock; // lock delegate
private NativeMethods._ShimUnlockCallback _pDelUnlock; // unlock delegate
#endif
private IntPtr _pShare; // share handle
private CurlShareLockCallback _pfLock; // client lock delegate
private CurlShareUnlockCallback _pfUnlock; // client unlock delegate
private IntPtr _ptrThis; // numeric handle
private Object _userData; // user data for delegates
/// <summary>
/// Constructor
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// This is thrown
/// if <see cref="Curl" /> hasn't bee properly initialized.
/// </exception>
/// <exception cref="System.NullReferenceException">
/// This is thrown if
/// the native <c>share</c> handle wasn't created successfully.
/// </exception>
public CurlShare()
{
Curl.EnsureCurl();
_pShare = NativeMethods.curl_share_init();
EnsureHandle();
LockFunction = null;
UnlockFunction = null;
UserData = null;
installDelegates();
}
public object UserData
{
get { return _userData; }
set { _userData = value; }
}
public CurlShareUnlockCallback UnlockFunction
{
get { return _pfUnlock; }
set { _pfUnlock = value; }
}
public CurlShareLockCallback LockFunction
{
get { return _pfLock; }
set { _pfLock = value; }
}
public CurlLockData Share
{
set { setShareOption(CurlShareOption.Share, value); }
}
public CurlLockData Unshare
{
set { setShareOption(CurlShareOption.Unshare, value); }
}
public CurlShareCode LastErrorCode
{
get { return _lastErrorCode; }
}
public string LastErrorDescription
{
get { return _lastErrorDescription; }
}
/// <summary>
/// Cleanup unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Destructor
/// </summary>
~CurlShare()
{
Dispose(false);
}
/// <summary>
/// Set options for this object.
/// </summary>
/// <param name="option">
/// One of the values in the <see cref="CurlShareOption" />
/// enumeration.
/// </param>
/// <param name="parameter">
/// An appropriate object based on the value passed in the
/// <c>option</c> argument. See <see cref="CurlShareOption" />
/// for more information about the appropriate parameter type.
/// </param>
/// <returns>
/// A <see cref="CurlShareCode" />, hopefully
/// <c>CurlShareCode.Ok</c>.
/// </returns>
/// <exception cref="System.NullReferenceException">
/// This is thrown if
/// the native <c>share</c> handle wasn't created successfully.
/// </exception>
public CurlShareCode SetOpt(CurlShareOption option, Object parameter)
{
EnsureHandle();
var retCode = CurlShareCode.Ok;
switch (option)
{
case CurlShareOption.LockFunction:
var lf = parameter as CurlShareLockCallback;
if (lf == null)
return CurlShareCode.BadOption;
_pfLock = lf;
break;
case CurlShareOption.UnlockFunction:
var ulf = parameter as CurlShareUnlockCallback;
if (ulf == null)
return CurlShareCode.BadOption;
_pfUnlock = ulf;
break;
case CurlShareOption.Share:
case CurlShareOption.Unshare:
{
var opt = (CurlLockData) Convert.ToInt32(parameter);
retCode = setShareOption(option, opt);
break;
}
case CurlShareOption.UserData:
_userData = parameter;
break;
default:
retCode = CurlShareCode.BadOption;
break;
}
return retCode;
}
private void setLastError(CurlShareCode code, CurlShareOption opt)
{
if (_lastErrorCode == CurlShareCode.Ok && code != CurlShareCode.Ok)
{
_lastErrorCode = code;
_lastErrorDescription = string.Format("Error: {0} setting option {1}", StrError(code), opt);
}
}
private CurlShareCode setShareOption(CurlShareOption option, CurlLockData value)
{
var retCode = (value != CurlLockData.Cookie) && (value != CurlLockData.Dns)
? CurlShareCode.BadOption
: NativeMethods.curl_share_setopt(_pShare, option, (IntPtr) value);
setLastError(retCode, option);
return retCode;
}
/// <summary>
/// Return a String description of an error code.
/// </summary>
/// <param name="errorNum">
/// The <see cref="CurlShareCode" /> for which to obtain the error
/// string description.
/// </param>
/// <returns>The string description.</returns>
public String StrError(CurlShareCode errorNum)
{
return Marshal.PtrToStringAnsi(NativeMethods.curl_share_strerror(errorNum));
}
private void Dispose(bool disposing)
{
lock (this)
{
// if (disposing) cleanup managed objects
if (_pShare != IntPtr.Zero)
{
#if USE_LIBCURLSHIM
NativeMethods.curl_shim_cleanup_share_delegates(_pShare);
#endif
NativeMethods.curl_share_cleanup(_pShare);
_hThis.Free();
_ptrThis = IntPtr.Zero;
_pShare = IntPtr.Zero;
}
}
}
internal IntPtr GetHandle()
{
return _pShare;
}
private void EnsureHandle()
{
if (_pShare == IntPtr.Zero)
throw new NullReferenceException("No internal share handle");
}
private void installDelegates()
{
_hThis = GCHandle.Alloc(this);
_ptrThis = (IntPtr)_hThis;
#if USE_LIBCURLSHIM
_pDelLock = LockDelegate;
_pDelUnlock = UnlockDelegate;
NativeMethods.curl_shim_install_share_delegates(_pShare, _ptrThis, _pDelLock, _pDelUnlock);
#endif
}
internal static void LockDelegate(int data, int access, IntPtr userPtr)
{
var gch = (GCHandle) userPtr;
var share = (CurlShare) gch.Target;
if (share == null)
return;
if (share.LockFunction == null)
return;
share.LockFunction((CurlLockData) data, (CurlLockAccess) access, share.UserData);
}
internal static void UnlockDelegate(int data, IntPtr userPtr)
{
var gch = (GCHandle) userPtr;
var share = (CurlShare) gch.Target;
if (share == null)
return;
if (share.UnlockFunction == null)
return;
share.UnlockFunction((CurlLockData) data, share.UserData);
}
}
}

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{74420A79-CC16-442C-8B1E-7C1B913844F0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CurlSharp</RootNamespace>
<AssemblyName>CurlSharp</AssemblyName>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;LINUX</DefineConstants>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>LINUX</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Curl.cs" />
<Compile Include="CurlEasy.cs" />
<Compile Include="CurlHttpMultiPartForm.cs" />
<Compile Include="CurlMulti.cs" />
<Compile Include="CurlMultiInfo.cs" />
<Compile Include="CurlShare.cs" />
<Compile Include="CurlSlist.cs" />
<Compile Include="CurlSslContext.cs" />
<Compile Include="CurlVersionInfoData.cs" />
<Compile Include="NativeMethods.cs" />
<Compile Include="Enums\CurlClosePolicy.cs" />
<Compile Include="Enums\CurlCode.cs" />
<Compile Include="Enums\CurlFormCode.cs" />
<Compile Include="Enums\CurlFormOption.cs" />
<Compile Include="Enums\CurlFtpAuth.cs" />
<Compile Include="Enums\CurlFtpSsl.cs" />
<Compile Include="Enums\CurlHttpAuth.cs" />
<Compile Include="Enums\CurlHttpVersion.cs" />
<Compile Include="Enums\CurlInfo.cs" />
<Compile Include="Enums\CurlInfoType.cs" />
<Compile Include="Enums\CurlInitFlag.cs" />
<Compile Include="Enums\CurlIoCommand.cs" />
<Compile Include="Enums\CurlIoError.cs" />
<Compile Include="Enums\CurlIpResolve.cs" />
<Compile Include="Enums\CurlLockAccess.cs" />
<Compile Include="Enums\CurlLockData.cs" />
<Compile Include="Enums\CurlMessage.cs" />
<Compile Include="Enums\CurlMultiCode.cs" />
<Compile Include="Enums\CurlNetrcOption.cs" />
<Compile Include="Enums\CurlOption.cs" />
<Compile Include="Enums\CurlProxyType.cs" />
<Compile Include="Enums\CurlShareCode.cs" />
<Compile Include="Enums\CurlShareOption.cs" />
<Compile Include="Enums\CurlSslVersion.cs" />
<Compile Include="Enums\CurlTimeCond.cs" />
<Compile Include="Enums\CurlVersion.cs" />
<Compile Include="Enums\CurlVersionFeatureBitmask.cs" />
<Compile Include="Callbacks\CurlEasyCallbacks.cs" />
<Compile Include="Callbacks\CurlShareCallbacks.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup />
<ProjectExtensions>
<MonoDevelop>
<Properties>
<Policies>
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentSwitchBody="True" IndentBlocksInsideExpressions="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
</Policies>
</Properties>
</MonoDevelop>
</ProjectExtensions>
</Project>

144
src/CurlSharp/CurlSlist.cs Normal file
View File

@@ -0,0 +1,144 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// This class wraps a linked list of strings used in <c>cURL</c>. Use it
/// to build string lists where they're required, such as when calling
/// <see cref="CurlEasy.SetOpt" /> with <see cref="CurlOption.Quote" />
/// as the option.
/// </summary>
public class CurlSlist : IDisposable
{
#if !USE_LIBCURLSHIM
[StructLayout(LayoutKind.Sequential)]
private class curl_slist
{
/// char*
[MarshalAs(UnmanagedType.LPStr)] public string data;
/// curl_slist*
public IntPtr next;
}
#endif
private IntPtr _handle;
/// <summary>
/// Constructor
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// This is thrown
/// if <see cref="Curl" /> hasn't bee properly initialized.
/// </exception>
public CurlSlist()
{
Curl.EnsureCurl();
_handle = IntPtr.Zero;
}
public CurlSlist(IntPtr handle)
{
_handle = handle;
}
/// <summary>
/// Read-only copy of the strings stored in the SList
/// </summary>
public List<string> Strings
{
get
{
if (_handle == IntPtr.Zero)
return null;
var strings = new List<string>();
#if !USE_LIBCURLSHIM
var slist = new curl_slist();
Marshal.PtrToStructure(_handle, slist);
while (true)
{
strings.Add(slist.data);
if (slist.next != IntPtr.Zero)
Marshal.PtrToStructure(slist.next, slist);
else
break;
}
#endif
return strings;
}
}
/// <summary>
/// Destructor
/// </summary>
~CurlSlist()
{
Dispose(false);
}
/// <summary>
/// Append a string to the list.
/// </summary>
/// <param name="str">The <c>string</c> to append.</param>
public void Append(string str)
{
#if USE_LIBCURLSHIM
_handle = NativeMethods.curl_shim_add_string_to_slist(_handle, str);
#else
_handle = NativeMethods.curl_slist_append(_handle, str);
#endif
}
/// <summary>
/// Free all internal strings.
/// </summary>
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
internal IntPtr Handle
{
get { return _handle; }
}
private void Dispose(bool disposing)
{
lock (this)
{
if (_handle != IntPtr.Zero)
{
#if USE_LIBCURLSHIM
NativeMethods.curl_shim_free_slist(_handle);
#else
NativeMethods.curl_slist_free_all(_handle);
#endif
_handle = IntPtr.Zero;
}
}
}
}
}

View File

@@ -0,0 +1,49 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
namespace CurlSharp
{
/// <summary>
/// An instance of this class is passed to the delegate
/// <see cref="CurlSslContextCallback" />, if it's implemented.
/// Within that delegate, the code will have to make native calls to
/// the <c>OpenSSL</c> library with the value returned from the
/// <see cref="CurlSslContext.Context" /> property cast to an
/// <c>SSL_CTX</c> pointer.
/// </summary>
public sealed class CurlSslContext
{
private readonly IntPtr _pvContext;
internal CurlSslContext(IntPtr pvContext)
{
_pvContext = pvContext;
}
/// <summary>
/// Get the underlying OpenSSL context.
/// </summary>
public IntPtr Context
{
get { return _pvContext; }
}
}
}

View File

@@ -0,0 +1,207 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
using System;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// This class wraps a <c>curl_version_info_data</c> struct. An instance is
/// obtained by calling <see cref="Curl.GetVersionInfo" />.
/// </summary>
public sealed class CurlVersionInfoData
{
private const int OFFSET_AGE = 0;
private const int OFFSET_VERSION = 4;
private const int OFFSET_VERSION_NUM = 8;
private const int OFFSET_HOST = 12;
private const int OFFSET_FEATURES = 16;
private const int OFFSET_SSL_VERSION = 20;
private const int OFFSET_SSL_VERSION_NUM = 24;
private const int OFFSET_LIBZ_VERSION = 28;
private const int OFFSET_PROTOCOLS = 32;
private const int OFFSET_ARES_VERSION = 36;
private const int OFFSET_ARES_VERSION_NUM = 40;
private const int OFFSET_LIBIDN_VERSION = 44;
private readonly IntPtr m_pVersionInfoData;
internal CurlVersionInfoData(CurlVersion ver)
{
m_pVersionInfoData = NativeMethods.curl_version_info(ver);
}
#if USE_LIBCURLSHIM
/// <summary>
/// Age of this struct, depending on how recent the linked-in
/// <c>libcurl</c> is, as a <see cref="CurlVersion" />.
/// </summary>
public CurlVersion Age
{
get { return (CurlVersion) NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_AGE); }
}
/// <summary>
/// Get the internal cURL version, as a <c>string</c>.
/// </summary>
public string Version
{
get
{
return Marshal.PtrToStringAnsi(
NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, OFFSET_VERSION));
}
}
/// <summary>
/// Get the internal cURL version number, a A 24-bit number created
/// like this: [8 bits major number] | [8 bits minor number] | [8
/// bits patch number]. For example, Version 7.12.2 is <c>0x070C02</c>.
/// </summary>
public int VersionNum
{
get { return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_VERSION_NUM); }
}
/// <summary>
/// Get the host information on which the underlying cURL was built.
/// </summary>
public string Host
{
get
{
return
Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, OFFSET_HOST));
}
}
/// <summary>
/// Get a bitmask of features, containing bits or'd from the
/// <see cref="CurlVersionFeatureBitmask" /> enumeration.
/// </summary>
public int Features
{
get { return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_FEATURES); }
}
/// <summary>
/// Get the Ssl version, if it's linked in.
/// </summary>
public string SslVersion
{
get
{
return
Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData,
OFFSET_SSL_VERSION));
}
}
/// <summary>
/// Get the Ssl version number, if Ssl is linked in.
/// </summary>
public int SSLVersionNum
{
get { return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_SSL_VERSION_NUM); }
}
/// <summary>
/// Get the libz version, if libz is linked in.
/// </summary>
public string LibZVersion
{
get
{
return
Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData,
OFFSET_LIBZ_VERSION));
}
}
/// <summary>
/// Get the names of the supported protocols.
/// </summary>
public string[] Protocols
{
get
{
var nProts = NativeMethods.curl_shim_get_number_of_protocols(
m_pVersionInfoData, OFFSET_PROTOCOLS);
var aProts = new String[nProts];
for (var i = 0; i < nProts; i++)
{
aProts[i] =
Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_protocol_string(m_pVersionInfoData,
OFFSET_PROTOCOLS, i));
}
return aProts;
}
}
/// <summary>
/// Get the ARes version, if ARes is linked in.
/// </summary>
public string ARes
{
get
{
if (Age > CurlVersion.First)
{
return
Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData,
OFFSET_ARES_VERSION));
}
return "n.a.";
}
}
/// <summary>
/// Get the ARes version number, if ARes is linked in.
/// </summary>
public int AResNum
{
get
{
if (Age > CurlVersion.First)
{
return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_ARES_VERSION_NUM);
}
return 0;
}
}
/// <summary>
/// Get the libidn version, if libidn is linked in.
/// </summary>
public string LibIdn
{
get
{
if (Age > CurlVersion.Second)
{
return
Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData,
OFFSET_LIBIDN_VERSION));
}
return "n.a.";
}
}
#endif
}
}

View File

@@ -0,0 +1,46 @@
namespace CurlSharp
{
/// <summary>
/// Contains values used to specify the order in which cached connections
/// are closed. One of these is passed as the
/// <see cref="CurlOption.ClosePolicy" /> option in a call
/// to <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlClosePolicy
{
/// <summary>
/// No close policy. Never use this.
/// </summary>
None = 0,
/// <summary>
/// Close the oldest cached connections first.
/// </summary>
Oldest = 1,
/// <summary>
/// Close the least recently used connections first.
/// </summary>
LeastRecentlyUsed = 2,
/// <summary>
/// Close the connections with the least traffic first.
/// </summary>
LeastTraffic = 3,
/// <summary>
/// Close the slowest connections first.
/// </summary>
Slowest = 4,
/// <summary>
/// Currently unimplemented.
/// </summary>
Callback = 5,
/// <summary>
/// End-of-enumeration marker; do not use in application code.
/// </summary>
Last = 6
};
}

View File

@@ -0,0 +1,403 @@
namespace CurlSharp
{
/// <summary>
/// Status code returned from <see cref="CurlEasy" /> functions.
/// </summary>
public enum CurlCode
{
/// <summary>
/// All fine. Proceed as usual.
/// </summary>
Ok = 0,
/// <summary>
/// Aborted by callback. An internal callback returned "abort"
/// to libcurl.
/// </summary>
AbortedByCallback = 42,
/// <summary>
/// Internal error. A function was called in a bad order.
/// </summary>
BadCallingOrder = 44,
/// <summary>
/// Unrecognized transfer encoding.
/// </summary>
BadContentEncoding = 61,
/// <summary>
/// Attempting FTP resume beyond file size.
/// </summary>
BadDownloadResume = 36,
/// <summary>
/// Internal error. A function was called with a bad parameter.
/// </summary>
BadFunctionArgument = 43,
/// <summary>
/// Bad password entered. An error was signaled when the password was
/// entered. This can also be the result of a "bad password" returned
/// from a specified password callback.
/// </summary>
BadPasswordEntered = 46,
/// <summary>
/// Failed to connect to host or proxy.
/// </summary>
CouldntConnect = 7,
/// <summary>
/// Couldn't resolve host. The given remote host was not resolved.
/// </summary>
CouldntResolveHost = 6,
/// <summary>
/// Couldn't resolve proxy. The given proxy host could not be resolved.
/// </summary>
CouldntResolveProxy = 5,
/// <summary>
/// Very early initialization code failed. This is likely to be an
/// internal error or problem.
/// </summary>
FailedInit = 2,
/// <summary>
/// Maximum file size exceeded.
/// </summary>
FilesizeExceeded = 63,
/// <summary>
/// A file given with FILE:// couldn't be opened. Most likely
/// because the file path doesn't identify an existing file. Did
/// you check file permissions?
/// </summary>
FileCouldntReadFile = 37,
/// <summary>
/// We were denied access when trying to login to an FTP server or
/// when trying to change working directory to the one given in the URL.
/// </summary>
FtpAccessDenied = 9,
/// <summary>
/// An internal failure to lookup the host used for the new
/// connection.
/// </summary>
FtpCantGetHost = 15,
/// <summary>
/// A bad return code on either PASV or EPSV was sent by the FTP
/// server, preventing libcurl from being able to continue.
/// </summary>
FtpCantReconnect = 16,
/// <summary>
/// The FTP SIZE command returned error. SIZE is not a kosher FTP
/// command, it is an extension and not all servers support it. This
/// is not a surprising error.
/// </summary>
FtpCouldntGetSize = 32,
/// <summary>
/// This was either a weird reply to a 'RETR' command or a zero byte
/// transfer complete.
/// </summary>
FtpCouldntRetrFile = 19,
/// <summary>
/// libcurl failed to set ASCII transfer type (TYPE A).
/// </summary>
FtpCouldntSetAscii = 29,
/// <summary>
/// Received an error when trying to set the transfer mode to binary.
/// </summary>
FtpCouldntSetBinary = 17,
/// <summary>
/// FTP couldn't STOR file. The server denied the STOR operation.
/// The error buffer usually contains the server's explanation to this.
/// </summary>
FtpCouldntStorFile = 25,
/// <summary>
/// The FTP REST command returned error. This should never happen
/// if the server is sane.
/// </summary>
FtpCouldntUseRest = 31,
/// <summary>
/// The FTP PORT command returned error. This mostly happen when
/// you haven't specified a good enough address for libcurl to use.
/// See <see cref="CurlOption.FtpPort" />.
/// </summary>
FtpPortFailed = 30,
/// <summary>
/// When sending custom "QUOTE" commands to the remote server, one
/// of the commands returned an error code that was 400 or higher.
/// </summary>
FtpQuoteError = 21,
/// <summary>
/// Requested FTP Ssl level failed.
/// </summary>
FtpSslFailed = 64,
/// <summary>
/// The FTP server rejected access to the server after the password
/// was sent to it. It might be because the username and/or the
/// password were incorrect or just that the server is not allowing
/// you access for the moment etc.
/// </summary>
FtpUserPasswordIncorrect = 10,
/// <summary>
/// FTP servers return a 227-line as a response to a PASV command.
/// If libcurl fails to parse that line, this return code is
/// passed back.
/// </summary>
FtpWeird227Format = 14,
/// <summary>
/// After having sent the FTP password to the server, libcurl expects
/// a proper reply. This error code indicates that an unexpected code
/// was returned.
/// </summary>
FtpWeirdPassReply = 11,
/// <summary>
/// libcurl failed to get a sensible result back from the server as
/// a response to either a PASV or a EPSV command. The server is flawed.
/// </summary>
FtpWeirdPasvReply = 13,
/// <summary>
/// After connecting to an FTP server, libcurl expects to get a
/// certain reply back. This error code implies that it got a strange
/// or bad reply. The given remote server is probably not an
/// OK FTP server.
/// </summary>
FtpWeirdServerReply = 8,
/// <summary>
/// After having sent user name to the FTP server, libcurl expects a
/// proper reply. This error code indicates that an unexpected code
/// was returned.
/// </summary>
FtpWeirdUserReply = 12,
/// <summary>
/// After a completed file transfer, the FTP server did not respond a
/// proper "transfer successful" code.
/// </summary>
FtpWriteError = 20,
/// <summary>
/// Function not found. A required LDAP function was not found.
/// </summary>
FunctionNotFound = 41,
/// <summary>
/// Nothing was returned from the server, and under the circumstances,
/// getting nothing is considered an error.
/// </summary>
GotNothing = 52,
/// <summary>
/// This is an odd error that mainly occurs due to internal confusion.
/// </summary>
HttpPostError = 34,
/// <summary>
/// The HTTP server does not support or accept range requests.
/// </summary>
HttpRangeError = 33,
/// <summary>
/// This is returned if <see cref="CurlOption.FailOnError" />
/// is set TRUE and the HTTP server returns an error code that
/// is >= 400.
/// </summary>
HttpReturnedError = 22,
/// <summary>
/// Interface error. A specified outgoing interface could not be
/// used. Set which interface to use for outgoing connections'
/// source IP address with <see cref="CurlOption.Interface" />.
/// </summary>
InterfaceFailed = 45,
/// <summary>
/// End-of-enumeration marker; do not use in client applications.
/// </summary>
Last = 67,
/// <summary>
/// LDAP cannot bind. LDAP bind operation failed.
/// </summary>
LdapCannotBind = 38,
/// <summary>
/// Invalid LDAP URL.
/// </summary>
LdapInvalidUrl = 62,
/// <summary>
/// LDAP search failed.
/// </summary>
LdapSearchFailed = 39,
/// <summary>
/// Library not found. The LDAP library was not found.
/// </summary>
LibraryNotFound = 40,
/// <summary>
/// Malformat user. User name badly specified. *Not currently used*
/// </summary>
MalformatUser = 24,
/// <summary>
/// This is not an error. This used to be another error code in an
/// old libcurl version and is currently unused.
/// </summary>
Obsolete = 50,
/// <summary>
/// Operation timeout. The specified time-out period was reached
/// according to the conditions.
/// </summary>
OperationTimeouted = 28,
/// <summary>
/// Out of memory. A memory allocation request failed. This is serious
/// badness and things are severely messed up if this ever occurs.
/// </summary>
OutOfMemory = 27,
/// <summary>
/// A file transfer was shorter or larger than expected. This
/// happens when the server first reports an expected transfer size,
/// and then delivers data that doesn't match the previously
/// given size.
/// </summary>
PartialFile = 18,
/// <summary>
/// There was a problem reading a local file or an error returned by
/// the read callback.
/// </summary>
ReadError = 26,
/// <summary>
/// Failure with receiving network data.
/// </summary>
RecvError = 56,
/// <summary>
/// Failed sending network data.
/// </summary>
SendError = 55,
/// <summary>
/// Sending the data requires a rewind that failed.
/// </summary>
SendFailRewind = 65,
/// <summary>
/// CurlShare is in use.
/// </summary>
ShareInUse = 57,
/// <summary>
/// Problem with the CA cert (path? access rights?)
/// </summary>
SslCaCert = 60,
/// <summary>
/// There's a problem with the local client certificate.
/// </summary>
SslCertProblem = 58,
/// <summary>
/// Couldn't use specified cipher.
/// </summary>
SslCipher = 59,
/// <summary>
/// A problem occurred somewhere in the Ssl/TLS handshake. You really
/// want to use the <see cref="CurlEasy.CurlDebugCallback" /> delegate and read
/// the message there as it pinpoints the problem slightly more. It
/// could be certificates (file formats, paths, permissions),
/// passwords, and others.
/// </summary>
SslConnectError = 35,
/// <summary>
/// Failed to initialize Ssl engine.
/// </summary>
SslEngineInitFailed = 66,
/// <summary>
/// The specified crypto engine wasn't found.
/// </summary>
SslEngineNotFound = 53,
/// <summary>
/// Failed setting the selected Ssl crypto engine as default!
/// </summary>
SslEngineSetFailed = 54,
/// <summary>
/// The remote server's Ssl certificate was deemed not OK.
/// </summary>
SslPeerCertificate = 51,
/// <summary>
/// A telnet option string was improperly formatted.
/// </summary>
TelnetOptionSyntax = 49,
/// <summary>
/// Too many redirects. When following redirects, libcurl hit the
/// maximum amount. Set your limit with
/// <see cref="CurlOption.MaxRedirs" />.
/// </summary>
TooManyRedirects = 47,
/// <summary>
/// An option set with <see cref="CurlOption.TelnetOptions" />
/// was not recognized/known. Refer to the appropriate documentation.
/// </summary>
UnknownTelnetOption = 48,
/// <summary>
/// The URL you passed to libcurl used a protocol that this libcurl
/// does not support. The support might be a compile-time option that
/// wasn't used, it can be a misspelled protocol string or just a
/// protocol libcurl has no code for.
/// </summary>
UnsupportedProtocol = 1,
/// <summary>
/// The URL was not properly formatted.
/// </summary>
UrlMalformat = 3,
/// <summary>
/// URL user malformatted. The user-part of the URL syntax was not
/// correct.
/// </summary>
UrlMalformatUser = 4,
/// <summary>
/// An error occurred when writing received data to a local file,
/// or an error was returned to libcurl from a write callback.
/// </summary>
WriteError = 23,
};
}

View File

@@ -0,0 +1,76 @@
/***************************************************************************
*
* Project: libcurl.NET
*
* Copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
* $Id: Enums.cs,v 1.1 2005/02/17 22:47:25 jeffreyphillips Exp $
**************************************************************************/
namespace CurlSharp
{
/// <summary>
/// One of these is returned by <see cref="CurlHttpMultiPartForm.AddSection" />.
/// </summary>
public enum CurlFormCode
{
/// <summary>
/// The section was added properly.
/// </summary>
Ok = 0,
/// <summary>
/// Out-of-memory when adding the section.
/// </summary>
Memory = 1,
/// <summary>
/// Invalid attempt to add the same option more than once to a
/// section.
/// </summary>
OptionTwice = 2,
/// <summary>
/// Invalid attempt to pass a <c>null</c> string or byte array in
/// one of the arguments.
/// </summary>
Null = 3,
/// <summary>
/// Invalid attempt to pass an unrecognized option in one of the
/// arguments.
/// </summary>
UnknownOption = 4,
/// <summary>
/// Incomplete argument lists.
/// </summary>
Incomplete = 5,
/// <summary>
/// Invalid attempt to provide a nested <c>Array</c>.
/// </summary>
IllegalArray = 6,
/// <summary>
/// This will not be returned so long as HTTP is enabled, which
/// it always is in libcurl.NET.
/// </summary>
Disabled = 7,
/// <summary>
/// End-of-enumeration marker; do not use in application code.
/// </summary>
Last = 8
};
}

View File

@@ -0,0 +1,142 @@
namespace CurlSharp
{
/// <summary>
/// These are options available to build a multi-part form section
/// in a call to <see cref="CurlHttpMultiPartForm.AddSection" />
/// </summary>
public enum CurlFormOption
{
/// <summary>
/// Another possibility to send options to
/// <see cref="CurlHttpMultiPartForm.AddSection" /> is this option, that
/// passes a <see cref="CurlForms" /> array reference as its value.
/// Each <see cref="CurlForms" /> array element has a
/// <see cref="CurlFormOption" /> and a <c>string</c>. All available
/// options can be used in an array, except the <c>Array</c>
/// option itself! The last argument in such an array must always be
/// <c>End</c>.
/// </summary>
Array = 8,
/// <summary>
/// Followed by a <c>string</c>, tells libcurl that a buffer is to be
/// used to upload data instead of using a file.
/// </summary>
Buffer = 11,
/// <summary>
/// Followed by an <c>int</c> with the size of the
/// <c>BufferPtr</c> byte array, tells libcurl the length of
/// the data to upload.
/// </summary>
BufferLength = 13,
/// <summary>
/// Followed by a <c>byte[]</c> array, tells libcurl the address of
/// the buffer containing data to upload (as indicated with
/// <c>Buffer</c>). You must also use
/// <c>BufferLength</c> to set the length of the buffer area.
/// </summary>
BufferPtr = 12,
/// <summary>
/// Specifies extra headers for the form POST section. This takes an
/// <see cref="CurlSlist" /> prepared in the usual way using
/// <see cref="CurlSlist.Append" /> and appends the list of headers to
/// those libcurl automatically generates.
/// </summary>
ContentHeader = 15,
/// <summary>
/// Followed by an <c>int</c> setting the length of the contents.
/// </summary>
ContentsLength = 6,
/// <summary>
/// Followed by a <c>string</c> with a content-type will make cURL
/// use this given content-type for this file upload part, possibly
/// instead of an internally chosen one.
/// </summary>
ContentType = 14,
/// <summary>
/// Followed by a <c>string</c> is used for the contents of this part, the
/// actual data to send away. If you'd like it to contain zero bytes,
/// you need to set the length of the name with
/// <c>ContentsLength</c>.
/// </summary>
CopyContents = 4,
/// <summary>
/// Followed by a <c>string</c> used to set the name of this part.
/// If you'd like it to contain zero bytes, you need to set the
/// length of the name with <c>NameLength</c>.
/// </summary>
CopyName = 1,
/// <summary>
/// This should be the last argument to a call to
/// <see cref="CurlHttpMultiPartForm.AddSection" />.
/// </summary>
End = 17,
/// <summary>
/// Followed by a file name, makes this part a file upload part. It
/// sets the file name field to the actual file name used here,
/// it gets the contents of the file and passes as data and sets the
/// content-type if the given file match one of the new internally
/// known file extension. For <c>File</c> the user may send
/// one or more files in one part by providing multiple <c>File</c>
/// arguments each followed by the filename (and each <c>File</c>
/// is allowed to have a <c>ContentType</c>).
/// </summary>
File = 10,
/// <summary>
/// Followed by a file name, and does the file read: the contents
/// will be used in as data in this part.
/// </summary>
FileContent = 7,
/// <summary>
/// Followed by a <c>string</c> file name, will make libcurl use the
/// given name in the file upload part, instead of the actual file
/// name given to <c>File</c>.
/// </summary>
Filename = 16,
/// <summary>
/// Followed by an <c>int</c> setting the length of the name.
/// </summary>
NameLength = 3,
/// <summary>
/// Not used.
/// </summary>
Nothing = 0,
/// <summary>
/// No longer used.
/// </summary>
Obsolete = 9,
/// <summary>
/// No longer used.
/// </summary>
Obsolete2 = 18,
/// <summary>
/// Followed by a <c>byte[]</c> used for the contents of this part.
/// If you'd like it to contain zero bytes, you need to set the
/// length of the name with <c>ContentsLength</c>.
/// </summary>
PtrContents = 5,
/// <summary>
/// Followed by a <c>byte[]</c> used for the name of this part.
/// If you'd like it to contain zero bytes, you need to set the
/// length of the name with <c>NameLength</c>.
/// </summary>
PtrName = 2
};
}

View File

@@ -0,0 +1,31 @@
namespace CurlSharp
{
/// <summary>
/// This enumeration contains values used to specify the FTP Ssl
/// authorization level using the
/// <see cref="CurlOption.FtpSslAuth" /> option when calling
/// <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlFtpAuth
{
/// <summary>
/// Let <c>libcurl</c> decide on the authorization scheme.
/// </summary>
Default = 0,
/// <summary>
/// Use "AUTH Ssl".
/// </summary>
SSL = 1,
/// <summary>
/// Use "AUTH TLS".
/// </summary>
TLS = 2,
/// <summary>
/// End-of-enumeration marker. Do not use in a client application.
/// </summary>
Last = 3
};
}

View File

@@ -0,0 +1,37 @@
namespace CurlSharp
{
/// <summary>
/// This enumeration contains values used to specify the FTP Ssl level
/// using the <see cref="CurlOption.FtpSsl" /> option when calling
/// <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlFtpSsl
{
/// <summary>
/// Don't attempt to use Ssl.
/// </summary>
None = 0,
/// <summary>
/// Try using Ssl, proceed as normal otherwise.
/// </summary>
Try = 1,
/// <summary>
/// Require Ssl for the control connection or fail with
/// <see cref="CurlCode.FtpSslFailed" />.
/// </summary>
Control = 2,
/// <summary>
/// Require Ssl for all communication or fail with
/// <see cref="CurlCode.FtpSslFailed" />.
/// </summary>
All = 3,
/// <summary>
/// End-of-enumeration marker. Do not use in a client application.
/// </summary>
Last = 4
};
}

View File

@@ -0,0 +1,65 @@
namespace CurlSharp
{
/// <summary>
/// This enumeration contains values used to specify the HTTP authentication
/// when using the <see cref="CurlOption.HttpAuth" /> option when
/// calling <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlHttpAuth
{
/// <summary>
/// No authentication.
/// </summary>
None = 0,
/// <summary>
/// HTTP Basic authentication. This is the default choice, and the
/// only method that is in wide-spread use and supported virtually
/// everywhere. This is sending the user name and password over the
/// network in plain text, easily captured by others.
/// </summary>
Basic = 1,
/// <summary>
/// HTTP Digest authentication. Digest authentication is defined
/// in RFC2617 and is a more secure way to do authentication over
/// public networks than the regular old-fashioned Basic method.
/// </summary>
Digest = 2,
/// <summary>
/// HTTP GSS-Negotiate authentication. The GSS-Negotiate (also known
/// as plain "Negotiate") method was designed by Microsoft and is
/// used in their web applications. It is primarily meant as a
/// support for Kerberos5 authentication but may be also used along
/// with another authentication methods. For more information see IETF
/// draft draft-brezak-spnego-http-04.txt.
/// <note>
/// You need to use a version of libcurl.NET built with a suitable
/// GSS-API library for this to work. This is not currently standard.
/// </note>
/// </summary>
GssNegotiate = 4,
/// <summary>
/// HTTP Ntlm authentication. A proprietary protocol invented and
/// used by Microsoft. It uses a challenge-response and hash concept
/// similar to Digest, to prevent the password from being eavesdropped.
/// </summary>
Ntlm = 8,
/// <summary>
/// This is a convenience macro that sets all bits and thus makes
/// libcurl pick any it finds suitable. libcurl will automatically
/// select the one it finds most secure.
/// </summary>
Any = 15, // ~0
/// <summary>
/// This is a convenience macro that sets all bits except Basic
/// and thus makes libcurl pick any it finds suitable. libcurl
/// will automatically select the one it finds most secure.
/// </summary>
AnySafe = 14 // ~Basic
};
}

View File

@@ -0,0 +1,31 @@
namespace CurlSharp
{
/// <summary>
/// Contains values used to specify the HTTP version level when using
/// the <see cref="CurlOption.HttpVersion" /> option in a call
/// to <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlHttpVersion
{
/// <summary>
/// We don't care about what version the library uses. libcurl will
/// use whatever it thinks fit.
/// </summary>
None = 0,
/// <summary>
/// Enforce HTTP 1.0 requests.
/// </summary>
Http1_0 = 1,
/// <summary>
/// Enforce HTTP 1.1 requests.
/// </summary>
Http1_1 = 2,
/// <summary>
/// Last entry in enumeration; do not use in application code.
/// </summary>
Last = 3
};
}

View File

@@ -0,0 +1,222 @@
namespace CurlSharp
{
/// <summary>
/// This enumeration is used to extract information associated with an
/// <see cref="CurlEasy" /> transfer. Specifically, a member of this
/// enumeration is passed as the first argument to
/// CurlEasy.GetInfo specifying the item to retrieve in the
/// second argument, which is a reference to an <c>int</c>, a
/// <c>double</c>, a <c>string</c>, a <c>DateTime</c> or an <c>object</c>.
/// </summary>
public enum CurlInfo
{
/// <summary>
/// The second argument receives the elapsed time, as a <c>double</c>,
/// in seconds, from the start until the connect to the remote host
/// (or proxy) was completed.
/// </summary>
ConnectTime = 0x300005,
/// <summary>
/// The second argument receives, as a <c>double</c>, the content-length
/// of the download. This is the value read from the Content-Length: field.
/// </summary>
ContentLengthDownload = 0x30000F,
/// <summary>
/// The second argument receives, as a <c>double</c>, the specified size
/// of the upload.
/// </summary>
ContentLengthUpload = 0x300010,
/// <summary>
/// The second argument receives, as a <c>string</c>, the content-type of
/// the downloaded object. This is the value read from the Content-Type:
/// field. If you get <c>null</c>, it means that the server didn't
/// send a valid Content-Type header or that the protocol used
/// doesn't support this.
/// </summary>
ContentType = 0x100012,
/// <summary>
/// The second argument receives, as a <c>string</c>, the last
/// used effective URL.
/// </summary>
EffectiveUrl = 0x100001,
/// <summary>
/// The second argument receives, as a <c>long</c>, the remote time
/// of the retrieved document. You should construct a <c>DateTime</c>
/// from this value, as shown in the <c>InfoDemo</c> sample. If you
/// get a date in the distant
/// past, it can be because of many reasons (unknown, the server
/// hides it or the server doesn't support the command that tells
/// document time etc) and the time of the document is unknown. Note
/// that you must tell the server to collect this information before
/// the transfer is made, by using the
/// <see cref="CurlOption.Filetime" /> option to
/// <see cref="CurlEasy.SetOpt" />. (Added in 7.5)
/// </summary>
Filetime = 0x20000E,
/// <summary>
/// The second argument receives an <c>int</c> specifying the total size
/// of all the headers received.
/// </summary>
HeaderSize = 0x20000B,
/// <summary>
/// The second argument receives, as an <c>int</c>, a bitmask indicating
/// the authentication method(s) available. The meaning of the bits is
/// explained in the documentation of
/// <see cref="CurlOption.HttpAuth" />. (Added in 7.10.8)
/// </summary>
HttpAuthAvail = 0x200017,
/// <summary>
/// The second argument receives an <c>int</c> indicating the numeric
/// connect code for the HTTP request.
/// </summary>
HttpConnectCode = 0x200016,
/// <summary>
/// End-of-enumeration marker; do not use in client applications.
/// </summary>
LastOne = 0x1C,
/// <summary>
/// The second argument receives, as a <c>double</c>, the time, in
/// seconds it took from the start until the name resolving was
/// completed.
/// </summary>
NameLookupTime = 0x300004,
/// <summary>
/// Never used.
/// </summary>
None = 0x0,
/// <summary>
/// The second argument receives an <c>int</c> indicating the
/// number of current connections. (Added in 7.13.0)
/// </summary>
NumConnects = 0x20001A,
/// <summary>
/// The second argument receives an <c>int</c> indicating the operating
/// system error number: <c>_errro</c> or <c>GetLastError()</c>,
/// depending on the platform. (Added in 7.12.2)
/// </summary>
OsErrno = 0x200019,
/// <summary>
/// The second argument receives, as a <c>double</c>, the time, in
/// seconds, it took from the start until the file transfer is just about
/// to begin. This includes all pre-transfer commands and negotiations
/// that are specific to the particular protocol(s) involved.
/// </summary>
PreTransferTime = 0x300006,
/// <summary>
/// The second argument receives a reference to the private data
/// associated with the <see cref="CurlEasy" /> object (set with the
/// <see cref="CurlOption.Private" /> option to
/// <see cref="CurlEasy.SetOpt" />. (Added in 7.10.3)
/// </summary>
Private = 0x100015,
/// <summary>
/// The second argument receives, as an <c>int</c>, a bitmask
/// indicating the authentication method(s) available for your
/// proxy authentication. This will be a bitmask of
/// <see cref="CurlHttpAuth" /> enumeration constants.
/// (Added in 7.10.8)
/// </summary>
ProxyAuthAvail = 0x200018,
/// <summary>
/// The second argument receives an <c>int</c> indicating the total
/// number of redirections that were actually followed. (Added in 7.9.7)
/// </summary>
RedirectCount = 0x200014,
/// <summary>
/// The second argument receives, as a <c>double</c>, the total time, in
/// seconds, for all redirection steps include name lookup, connect,
/// pretransfer and transfer before final transaction was started.
/// <c>RedirectTime</c> contains the complete execution
/// time for multiple redirections. (Added in 7.9.7)
/// </summary>
RedirectTime = 0x300013,
/// <summary>
/// The second argument receives an <c>int</c> containing the total size
/// of the issued requests. This is so far only for HTTP requests. Note
/// that this may be more than one request if
/// <see cref="CurlOption.FollowLocation" /> is <c>true</c>.
/// </summary>
RequestSize = 0x20000C,
/// <summary>
/// The second argument receives an <c>int</c> with the last received HTTP
/// or FTP code. This option was known as <c>CURLINFO_HTTP_CODE</c> in
/// libcurl 7.10.7 and earlier.
/// </summary>
ResponseCode = 0x200002,
/// <summary>
/// The second argument receives a <c>double</c> with the total amount of
/// bytes that were downloaded. The amount is only for the latest transfer
/// and will be reset again for each new transfer.
/// </summary>
SizeDownload = 0x300008,
/// <summary>
/// The second argument receives a <c>double</c> with the total amount
/// of bytes that were uploaded.
/// </summary>
SizeUpload = 0x300007,
/// <summary>
/// The second argument receives a <c>double</c> with the average
/// download speed that cURL measured for the complete download.
/// </summary>
SpeedDownload = 0x300009,
/// <summary>
/// The second argument receives a <c>double</c> with the average
/// upload speed that libcurl measured for the complete upload.
/// </summary>
SpeedUpload = 0x30000A,
/// <summary>
/// The second argument receives an <see cref="CurlSlist" /> containing
/// the names of the available Ssl engines.
/// </summary>
SslEngines = 0x40001B,
/// <summary>
/// The second argument receives an <c>int</c> with the result of
/// the certificate verification that was requested (using the
/// <see cref="CurlOption.SslVerifyPeer" /> option in
/// <see cref="CurlEasy.SetOpt" />.
/// </summary>
SslVerifyResult = 0x20000D,
/// <summary>
/// The second argument receives a <c>double</c> specifying the time,
/// in seconds, from the start until the first byte is just about to be
/// transferred. This includes <c>PreTransferTime</c> and
/// also the time the server needs to calculate the result.
/// </summary>
StartTransferTime = 0x300011,
/// <summary>
/// The second argument receives a <c>double</c> indicating the total transaction
/// time in seconds for the previous transfer. This time does not include
/// the connect time, so if you want the complete operation time,
/// you should add the <c>ConnectTime</c>.
/// </summary>
TotalTime = 0x300003,
};
}

View File

@@ -0,0 +1,50 @@
namespace CurlSharp
{
/// <summary>
/// A member of this enumeration is passed as the first parameter to the
/// <see cref="CurlEasy.CurlDebugCallback" /> delegate to which libcurl passes
/// debug messages.
/// </summary>
public enum CurlInfoType
{
/// <summary>
/// The data is informational text.
/// </summary>
Text = 0,
/// <summary>
/// The data is header (or header-like) data received from the peer.
/// </summary>
HeaderIn = 1,
/// <summary>
/// The data is header (or header-like) data sent to the peer.
/// </summary>
HeaderOut = 2,
/// <summary>
/// The data is protocol data received from the peer.
/// </summary>
DataIn = 3,
/// <summary>
/// The data is protocol data sent to the peer.
/// </summary>
DataOut = 4,
/// <summary>
/// The data is Ssl-related data sent to the peer.
/// </summary>
SslDataIn = 5,
/// <summary>
/// The data is Ssl-related data received from the peer.
/// </summary>
SslDataOut = 6,
/// <summary>
/// End of enumeration marker, don't use in a client application.
/// </summary>
End = 7
};
}

View File

@@ -0,0 +1,34 @@
namespace CurlSharp
{
/// <summary>
/// Contains values used to initialize libcurl internally. One of
/// these is passed in the call to <see cref="Curl.GlobalInit" />.
/// </summary>
public enum CurlInitFlag
{
/// <summary>
/// Initialise nothing extra. This sets no bit.
/// </summary>
Nothing = 0,
/// <summary>
/// Initialize Ssl.
/// </summary>
Ssl = 1,
/// <summary>
/// Initialize the Win32 socket libraries.
/// </summary>
Win32 = 2,
/// <summary>
/// Initialize everything possible. This sets all known bits.
/// </summary>
All = 3,
/// <summary>
/// Equivalent to <c>All</c>.
/// </summary>
Default = All
};
}

View File

@@ -0,0 +1,27 @@
namespace CurlSharp
{
/// <summary>
/// Your handler for the <see cref="CurlEasy.CurlIoctlCallback" />
/// delegate is passed one of these values as its first parameter.
/// Right now, the only supported value is
/// <code>RestartRead</code>.
/// </summary>
public enum CurlIoCommand
{
/// <summary>
/// No IOCTL operation; we should never see this.
/// </summary>
Nop = 0,
/// <summary>
/// When this is sent, your callback may need to, for example,
/// rewind a local file that is being sent via FTP.
/// </summary>
RestartRead = 1,
/// <summary>
/// End of enumeration marker, don't use in a client application.
/// </summary>
Last = 2
}
}

View File

@@ -0,0 +1,30 @@
namespace CurlSharp
{
/// <summary>
/// Your handler for the <see cref="CurlEasy.CurlIoctlCallback" /> delegate
/// should return a member of this enumeration.
/// </summary>
public enum CurlIoError
{
/// <summary>
/// Indicate that the callback processed everything okay.
/// </summary>
Ok = 0,
/// <summary>
/// Unknown command sent to callback. Right now, only
/// <code>RestartRead</code> is supported.
/// </summary>
UnknownCommand = 1,
/// <summary>
/// Indicate to libcurl that a restart failed.
/// </summary>
FailRestart = 2,
/// <summary>
/// End of enumeration marker, don't use in a client application.
/// </summary>
Last = 3
}
}

View File

@@ -0,0 +1,26 @@
namespace CurlSharp
{
/// <summary>
/// This enumeration contains values used to specify the IP resolution
/// method when using the <see cref="CurlOption.IpResolve" />
/// option in a call to <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlIpResolve
{
/// <summary>
/// Default, resolves addresses to all IP versions that your system
/// allows.
/// </summary>
Whatever = 0,
/// <summary>
/// Resolve to ipv4 addresses.
/// </summary>
V4 = 1,
/// <summary>
/// Resolve to ipv6 addresses.
/// </summary>
V6 = 2
};
}

View File

@@ -0,0 +1,31 @@
namespace CurlSharp
{
/// <summary>
/// Values containing the type of shared access requested when libcurl
/// calls the <see cref="CurlShare.CurlShareLockCallback" /> delegate.
/// </summary>
public enum CurlLockAccess
{
/// <summary>
/// Unspecified action; the delegate should never receive this.
/// </summary>
None = 0,
/// <summary>
/// The delegate receives this call when libcurl is requesting
/// read access to the shared resource.
/// </summary>
Shared = 1,
/// <summary>
/// The delegate receives this call when libcurl is requesting
/// write access to the shared resource.
/// </summary>
Single = 2,
/// <summary>
/// End-of-enumeration marker; do not use in application code.
/// </summary>
Last = 3
};
}

View File

@@ -0,0 +1,48 @@
namespace CurlSharp
{
/// <summary>
/// Members of this enumeration should be passed to
/// <see cref="CurlShare.SetOpt" /> when it is called with the
/// <c>CurlShare</c> or <c>Unshare</c> options
/// provided in the <see cref="CurlShareOption" /> enumeration.
/// </summary>
public enum CurlLockData
{
/// <summary>
/// Not used.
/// </summary>
None = 0,
/// <summary>
/// Used internally by libcurl.
/// </summary>
Share = 1,
/// <summary>
/// Cookie data will be shared across the <see cref="CurlEasy" /> objects
/// using this shared object.
/// </summary>
Cookie = 2,
/// <summary>
/// Cached Dns hosts will be shared across the <see cref="CurlEasy" />
/// objects using this shared object.
/// </summary>
Dns = 3,
/// <summary>
/// Not supported yet.
/// </summary>
SslSession = 4,
/// <summary>
/// Not supported yet.
/// </summary>
Connect = 5,
/// <summary>
/// End-of-enumeration marker; do not use in application code.
/// </summary>
Last = 6
};
}

View File

@@ -0,0 +1,25 @@
namespace CurlSharp
{
/// <summary>
/// The status code associated with an <see cref="CurlEasy" /> object in a
/// <see cref="CurlMulti" /> operation. One of these is returned in response
/// to reading the <see cref="CurlMultiInfo.Msg" /> property.
/// </summary>
public enum CurlMessage
{
/// <summary>
/// First entry in the enumeration, not used.
/// </summary>
None = 0,
/// <summary>
/// The associated <see cref="CurlEasy" /> object completed.
/// </summary>
Done = 1,
/// <summary>
/// End-of-enumeration marker, not used.
/// </summary>
Last = 2
};
}

View File

@@ -0,0 +1,46 @@
namespace CurlSharp
{
/// <summary>
/// Contains return codes for many of the functions in the
/// <see cref="CurlMulti" /> class.
/// </summary>
public enum CurlMultiCode
{
/// <summary>
/// You should call <see cref="CurlMulti.Perform" /> again before calling
/// <see cref="CurlMulti.Select" />.
/// </summary>
CallMultiPerform = -1,
/// <summary>
/// The function succeded.
/// </summary>
Ok = 0,
/// <summary>
/// The internal <see cref="CurlMulti" /> is bad.
/// </summary>
BadHandle = 1,
/// <summary>
/// One of the <see cref="CurlEasy" /> handles associated with the
/// <see cref="CurlMulti" /> object is bad.
/// </summary>
BadEasyHandle = 2,
/// <summary>
/// Out of memory. This is a severe problem.
/// </summary>
OutOfMemory = 3,
/// <summary>
/// Internal error deep within the libcurl library.
/// </summary>
InternalError = 4,
/// <summary>
/// End-of-enumeration marker, not used.
/// </summary>
Last = 5
};
}

View File

@@ -0,0 +1,43 @@
namespace CurlSharp
{
/// <summary>
/// Contains values used to specify the preference of libcurl between
/// using user names and passwords from your ~/.netrc file, relative to
/// user names and passwords in the URL supplied with
/// <see cref="CurlOption.Url" />. This is passed when using
/// the <see cref="CurlOption.Netrc" /> option in a call
/// to <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlNetrcOption
{
/// <summary>
/// The library will ignore the file and use only the information
/// in the URL. This is the default.
/// </summary>
Ignored = 0,
/// <summary>
/// The use of your ~/.netrc file is optional, and information in the
/// URL is to be preferred. The file will be scanned with the host
/// and user name (to find the password only) or with the host only,
/// to find the first user name and password after that machine,
/// which ever information is not specified in the URL.
/// <para>
/// Undefined values of the option will have this effect.
/// </para>
/// </summary>
Optional = 1,
/// <summary>
/// This value tells the library that use of the file is required,
/// to ignore the information in the URL, and to search the file
/// with the host only.
/// </summary>
Required = 2,
/// <summary>
/// Last entry in enumeration; do not use in application code.
/// </summary>
Last = 3
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
namespace CurlSharp
{
/// <summary>
/// This enumeration contains values used to specify the proxy type when
/// using the <see cref="CurlOption.Proxy" /> option when calling
/// <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlProxyType
{
/// <summary>
/// Ordinary HTTP proxy.
/// </summary>
Http = 0,
/// <summary>
/// Use if the proxy supports SOCKS4 user authentication. If you're
/// unfamiliar with this, consult your network administrator.
/// </summary>
Socks4 = 4,
/// <summary>
/// Use if the proxy supports SOCKS5 user authentication. If you're
/// unfamiliar with this, consult your network administrator.
/// </summary>
Socks5 = 5
};
}

View File

@@ -0,0 +1,40 @@
namespace CurlSharp
{
/// <summary>
/// Contains return codes from many of the functions in the
/// <see cref="CurlShare" /> class.
/// </summary>
public enum CurlShareCode
{
/// <summary>
/// The function succeeded.
/// </summary>
Ok = 0,
/// <summary>
/// A bad option was passed to <see cref="CurlShare.SetOpt" />.
/// </summary>
BadOption = 1,
/// <summary>
/// An attempt was made to pass an option to
/// <see cref="CurlShare.SetOpt" /> while the CurlShare object is in use.
/// </summary>
InUse = 2,
/// <summary>
/// The <see cref="CurlShare" /> object's internal handle is invalid.
/// </summary>
Invalid = 3,
/// <summary>
/// Out of memory. This is a severe problem.
/// </summary>
NoMem = 4,
/// <summary>
/// End-of-enumeration marker; do not use in application code.
/// </summary>
Last = 5
};
}

View File

@@ -0,0 +1,53 @@
namespace CurlSharp
{
/// <summary>
/// A member of this enumeration is passed to the function
/// <see cref="CurlShare.SetOpt" /> to configure a <see cref="CurlShare" />
/// transfer.
/// </summary>
public enum CurlShareOption
{
/// <summary>
/// Start-of-enumeration; do not use in application code.
/// </summary>
None = 0,
/// <summary>
/// The parameter, which should be a member of the
/// <see cref="CurlLockData" /> enumeration, specifies a type of
/// data that should be shared.
/// </summary>
Share = 1,
/// <summary>
/// The parameter, which should be a member of the
/// <see cref="CurlLockData" /> enumeration, specifies a type of
/// data that should be unshared.
/// </summary>
Unshare = 2,
/// <summary>
/// The parameter should be a reference to a
/// <see cref="CurlShare.CurlShareLockCallback" /> delegate.
/// </summary>
LockFunction = 3,
/// <summary>
/// The parameter should be a reference to a
/// <see cref="CurlShare.CurlShareUnlockCallback" /> delegate.
/// </summary>
UnlockFunction = 4,
/// <summary>
/// The parameter allows you to specify an object reference that
/// will passed to the <see cref="CurlShare.CurlShareLockCallback" /> delegate and
/// the <see cref="CurlShare.CurlShareUnlockCallback" /> delegate.
/// </summary>
UserData = 5,
/// <summary>
/// End-of-enumeration; do not use in application code.
/// </summary>
Last = 6
};
}

View File

@@ -0,0 +1,36 @@
namespace CurlSharp
{
/// <summary>
/// Contains values used to specify the Ssl version level when using
/// the <see cref="CurlOption.SslVersion" /> option in a call
/// to <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlSslVersion
{
/// <summary>
/// Use whatever version the Ssl library selects.
/// </summary>
Default = 0,
/// <summary>
/// Use TLS version 1.
/// </summary>
Tlsv1 = 1,
/// <summary>
/// Use Ssl version 2. This is not a good option unless it's the
/// only version supported by the remote server.
/// </summary>
Sslv2 = 2,
/// <summary>
/// Use Ssl version 3. This is a preferred option.
/// </summary>
Sslv3 = 3,
/// <summary>
/// Last entry in enumeration; do not use in application code.
/// </summary>
Last = 4
};
}

View File

@@ -0,0 +1,39 @@
namespace CurlSharp
{
/// <summary>
/// Contains values used to specify the time condition when using
/// the <see cref="CurlOption.TimeCondition" /> option in a call
/// to <see cref="CurlEasy.SetOpt" />
/// </summary>
public enum CurlTimeCond
{
/// <summary>
/// Use no time condition.
/// </summary>
None = 0,
/// <summary>
/// The time condition is true if the resource has been modified
/// since the date/time passed in
/// <see cref="CurlOption.TimeValue" />.
/// </summary>
IfModSince = 1,
/// <summary>
/// True if the resource has not been modified since the date/time
/// passed in <see cref="CurlOption.TimeValue" />.
/// </summary>
IfUnmodSince = 2,
/// <summary>
/// True if the resource's last modification date/time equals that
/// passed in <see cref="CurlOption.TimeValue" />.
/// </summary>
LastMod = 3,
/// <summary>
/// Last entry in enumeration; do not use in application code.
/// </summary>
Last = 4
};
}

View File

@@ -0,0 +1,34 @@
namespace CurlSharp
{
/// <summary>
/// A member of this enumeration is passed to the function
/// <see cref="Curl.GetVersionInfo" />
/// </summary>
public enum CurlVersion
{
/// <summary>
/// Capabilities associated with the initial version of libcurl.
/// </summary>
First = 0,
/// <summary>
/// Capabilities associated with the second version of libcurl.
/// </summary>
Second = 1,
/// <summary>
/// Capabilities associated with the third version of libcurl.
/// </summary>
Third = 2,
/// <summary>
/// Same as <c>Third</c>.
/// </summary>
Now = Third,
/// <summary>
/// End-of-enumeration marker; do not use in application code.
/// </summary>
Last = 3
};
}

View File

@@ -0,0 +1,71 @@
namespace CurlSharp
{
/// <summary>
/// A bitmask of libcurl features OR'd together as the value of the
/// property <see cref="CurlVersionInfoData.Features" />. The feature
/// bits are summarized in the table below.
/// </summary>
public enum CurlVersionFeatureBitmask
{
/// <summary>
/// Supports Ipv6.
/// </summary>
Ipv6 = 0x01,
/// <summary>
/// Supports kerberos4 (when using FTP).
/// </summary>
Kerberos64 = 0x02,
/// <summary>
/// Supports Ssl (HTTPS/FTPS).
/// </summary>
Ssl = 0x04,
/// <summary>
/// Supports HTTP deflate using libz.
/// </summary>
LibZ = 0x08,
/// <summary>
/// Supports HTTP Ntlm (added in 7.10.6).
/// </summary>
Ntlm = 0x10,
/// <summary>
/// Supports HTTP GSS-Negotiate (added in 7.10.6).
/// </summary>
GssNegotiate = 0x20,
/// <summary>
/// libcurl was built with extra debug capabilities built-in. This
/// is mainly of interest for libcurl hackers. (added in 7.10.6)
/// </summary>
Debug = 0x40,
/// <summary>
/// libcurl was built with support for asynchronous name lookups,
/// which allows more exact timeouts (even on Windows) and less
/// blocking when using the multi interface. (added in 7.10.7)
/// </summary>
AsynchDns = 0x80,
/// <summary>
/// libcurl was built with support for Spnego authentication
/// (Simple and Protected GSS-API Negotiation Mechanism, defined
/// in RFC 2478.) (added in 7.10.8)
/// </summary>
Spnego = 0x100,
/// <summary>
/// libcurl was built with support for large files.
/// </summary>
LargeFile = 0x200,
/// <summary>
/// libcurl was built with support for IDNA, domain names with
/// international letters.
/// </summary>
Idn = 0x400
};
}

View File

@@ -0,0 +1,402 @@
/***************************************************************************
*
* CurlS#arp
*
* Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com)
* Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net)
*
* This software is licensed as described in the file LICENSE, which you
* should have received as part of this distribution.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of this Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the LICENSE file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
* ANY KIND, either express or implied.
*
**************************************************************************/
//#define USE_LIBCURLSHIM
using System;
using System.Runtime.InteropServices;
namespace CurlSharp
{
/// <summary>
/// P/Invoke signatures.
/// </summary>
internal static unsafe class NativeMethods
{
#if WIN64
private const string CURL_LIB = "libcurl64.dll";
#if USE_LIBCURLSHIM
private const string CURLSHIM_LIB = "libcurlshim64.dll";
#endif
#else
#if LINUX
private const string CURL_LIB = "libcurl";
#else
private const string CURL_LIB = "libcurl.dll";
#if USE_LIBCURLSHIM
private const string CURLSHIM_LIB = "libcurlshim.dll";
#endif
#endif
#endif
#if !USE_LIBCURLSHIM
#if LINUX
private const string WINSOCK_LIB = "libc";
#else
private const string WINSOCK_LIB = "ws2_32.dll";
#endif
#endif
// internal delegates from cURL
// libcurl imports
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_global_init (int flags);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_global_cleanup ();
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr curl_escape (String url, int length);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr curl_unescape (String url, int length);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_free (IntPtr p);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_version ();
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_easy_init ();
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_easy_cleanup (IntPtr pCurl);
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
internal delegate int _CurlGenericCallback (IntPtr ptr, int sz, int nmemb, IntPtr userdata);
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
internal delegate int _CurlProgressCallback (
IntPtr extraData, double dlTotal, double dlNow, double ulTotal, double ulNow);
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
internal delegate int _CurlDebugCallback (
IntPtr ptrCurl, CurlInfoType infoType, string message, int size, IntPtr ptrUserData);
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
internal delegate int _CurlSslCtxCallback (IntPtr ctx, IntPtr parm);
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
internal delegate CurlIoError _CurlIoctlCallback (CurlIoCommand cmd, IntPtr parm);
// curl_easy_setopt() overloads
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, IntPtr parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, string parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, byte[] parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, long parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, bool parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")]
internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlGenericCallback parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")]
internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlProgressCallback parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")]
internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlDebugCallback parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")]
internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlSslCtxCallback parm);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")]
internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlIoctlCallback parm);
#if !USE_LIBCURLSHIM
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlMultiCode curl_multi_fdset (IntPtr pmulti,
[In, Out] ref fd_set read_fd_set,
[In, Out] ref fd_set write_fd_set,
[In, Out] ref fd_set exc_fd_set,
[In, Out] ref int max_fd);
[StructLayout (LayoutKind.Sequential)]
internal struct fd_set
{
internal uint fd_count;
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = FD_SETSIZE)] internal IntPtr[] fd_array;
internal fixed uint fd_array[FD_SETSIZE];
internal const int FD_SETSIZE = 64;
internal void Cleanup ()
{
//fd_array = null;
}
internal static fd_set Create ()
{
return new fd_set {
//fd_array = new IntPtr[FD_SETSIZE],
fd_count = 0
};
}
internal static fd_set Create (IntPtr socket)
{
var handle = Create ();
handle.fd_count = 1;
handle.fd_array [0] = (uint)socket;
return handle;
}
}
internal static void FD_ZERO (fd_set fds)
{
for (var i = 0; i < fd_set.FD_SETSIZE; i++) {
//fds.fd_array[i] = (IntPtr) 0;
fds.fd_array [i] = 0;
}
fds.fd_count = 0;
}
[StructLayout (LayoutKind.Sequential)]
internal struct timeval
{
/// <summary>
/// Time interval, in seconds.
/// </summary>
internal int tv_sec;
/// <summary>
/// Time interval, in microseconds.
/// </summary>
internal int tv_usec;
internal static timeval Create (int milliseconds)
{
return new timeval {
tv_sec = milliseconds / 1000,
tv_usec = (milliseconds % 1000) * 1000
};
}
};
[DllImport (WINSOCK_LIB, EntryPoint = "select")]
internal static extern int select (
int nfds, // number of sockets, (ignored in winsock)
[In, Out] ref fd_set readfds, // read sockets to watch
[In, Out] ref fd_set writefds, // write sockets to watch
[In, Out] ref fd_set exceptfds, // error sockets to watch
ref timeval timeout);
//[DllImport(WINSOCK_LIB, EntryPoint = "select")]
//internal static extern int select(int ndfs, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout);
#endif
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_perform (IntPtr pCurl);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_easy_duphandle (IntPtr pCurl);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_easy_strerror (CurlCode err);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_getinfo (IntPtr pCurl, CurlInfo info, ref IntPtr pInfo);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlCode curl_easy_getinfo (IntPtr pCurl, CurlInfo info, ref double dblVal);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_easy_reset (IntPtr pCurl);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_multi_init ();
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlMultiCode curl_multi_cleanup (IntPtr pmulti);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlMultiCode curl_multi_add_handle (IntPtr pmulti, IntPtr peasy);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlMultiCode curl_multi_remove_handle (IntPtr pmulti, IntPtr peasy);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_multi_strerror (CurlMultiCode errorNum);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlMultiCode curl_multi_perform (IntPtr pmulti, ref int runningHandles);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_formfree (IntPtr pForm);
#if !USE_LIBCURLSHIM
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_formadd (ref IntPtr pHttppost, ref IntPtr pLastPost,
int codeFirst, IntPtr bufFirst,
int codeNext, IntPtr bufNext,
int codeLast);
#endif
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_share_init ();
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlShareCode curl_share_cleanup (IntPtr pShare);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_share_strerror (CurlShareCode errorCode);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlShareCode curl_share_setopt (IntPtr pShare, CurlShareOption optCode, IntPtr option);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr curl_slist_append (IntPtr slist, string data);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlShareCode curl_slist_free_all (IntPtr pList);
[DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_version_info (CurlVersion ver);
#if USE_LIBCURLSHIM
// libcurlshim imports
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_initialize();
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_cleanup();
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_shim_alloc_strings();
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
internal static extern IntPtr curl_shim_add_string_to_slist(
IntPtr pStrings, String str);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
internal static extern IntPtr curl_shim_get_string_from_slist(
IntPtr pSlist, ref IntPtr pStr);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
internal static extern IntPtr curl_shim_add_string(IntPtr pStrings, String str);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_free_strings(IntPtr pStrings);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_shim_install_delegates(IntPtr pCurl, IntPtr pThis,
_ShimWriteCallback pWrite, _ShimReadCallback pRead,
_ShimProgressCallback pProgress, _ShimDebugCallback pDebug,
_ShimHeaderCallback pHeader, _ShimSslCtxCallback pCtx,
_ShimIoctlCallback pIoctl);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_cleanup_delegates(IntPtr pThis);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_get_file_time(int unixTime,
ref int yy, ref int mm, ref int dd, ref int hh, ref int mn, ref int ss);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_free_slist(IntPtr p);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_shim_alloc_fd_sets();
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_free_fd_sets(IntPtr fdsets);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern CurlMultiCode curl_shim_multi_fdset(IntPtr multi,
IntPtr fdsets, ref int maxFD);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_shim_select(int maxFD, IntPtr fdsets,
int milliseconds);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_shim_multi_info_read(IntPtr multi,
ref int nMsgs);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_multi_info_free(IntPtr multiInfo);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_shim_formadd(IntPtr[] ppForms, IntPtr[] pParams, int nParams);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_shim_install_share_delegates(IntPtr pShare,
IntPtr pThis, _ShimLockCallback pLock, _ShimUnlockCallback pUnlock);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern void curl_shim_cleanup_share_delegates(IntPtr pShare);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_shim_get_version_int_value(IntPtr p, int offset);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_shim_get_version_char_ptr(IntPtr p, int offset);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern int curl_shim_get_number_of_protocols(IntPtr p, int offset);
[DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr curl_shim_get_protocol_string(IntPtr p, int offset, int index);
internal delegate void _ShimLockCallback(int data, int access, IntPtr userPtr);
internal delegate void _ShimUnlockCallback(int data, IntPtr userPtr);
internal delegate int _ShimDebugCallback(CurlInfoType infoType, IntPtr msgBuf, int msgBufSize, IntPtr parm);
internal delegate int _ShimHeaderCallback(IntPtr buf, int sz, int nmemb, IntPtr stream);
internal delegate CurlIoError _ShimIoctlCallback(CurlIoCommand cmd, IntPtr parm);
internal delegate int _ShimProgressCallback(IntPtr parm, double dlTotal, double dlNow, double ulTotal, double ulNow);
internal delegate int _ShimReadCallback(IntPtr buf, int sz, int nmemb, IntPtr parm);
internal delegate int _ShimSslCtxCallback(IntPtr ctx, IntPtr parm);
internal delegate int _ShimWriteCallback(IntPtr buf, int sz, int nmemb, IntPtr parm);
#endif
}
}

View File

@@ -0,0 +1,22 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle ("CurlSharp")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]
[assembly: AssemblyProduct ("")]
[assembly: AssemblyCopyright ("max")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion ("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@@ -1,604 +0,0 @@
//********************************************************************************************
//Author: Sergey Stoyan, CliverSoft.com
// http://cliversoft.com
// stoyan@cliversoft.com
// sergey.stoyan@gmail.com
// 27 February 2007
//********************************************************************************************
using System;
using System.Text.RegularExpressions;
// ReSharper disable NotAccessedField.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
namespace DateTimeRoutines
{
/// <summary>
/// Miscellaneous and parsing methods for DateTime
/// </summary>
public static class DateTimeRoutines
{
#region miscellaneous methods
/// <summary>
/// Amount of seconds elapsed between 1970-01-01 00:00:00 and the date-time.
/// </summary>
/// <param name="dateTime">date-time</param>
/// <returns>seconds</returns>
public static uint GetSecondsSinceUnixEpoch(this DateTime dateTime)
{
var t = dateTime - new DateTime(1970, 1, 1);
var ss = (int)t.TotalSeconds;
if (ss < 0)
return 0;
return (uint)ss;
}
#endregion
#region parsing definitions
/// <summary>
/// Defines a substring where date-time was found and result of conversion
/// </summary>
public class ParsedDateTime
{
/// <summary>
/// Index of first char of a date substring found in the string
/// </summary>
public readonly int IndexOfDate;
/// <summary>
/// Length a date substring found in the string
/// </summary>
public readonly int LengthOfDate;
/// <summary>
/// Index of first char of a time substring found in the string
/// </summary>
public readonly int IndexOfTime;
/// <summary>
/// Length of a time substring found in the string
/// </summary>
public readonly int LengthOfTime;
/// <summary>
/// DateTime found in the string
/// </summary>
public readonly DateTime DateTime;
/// <summary>
/// True if a date was found within the string
/// </summary>
public readonly bool IsDateFound;
/// <summary>
/// True if a time was found within the string
/// </summary>
public readonly bool IsTimeFound;
/// <summary>
/// UTC offset if it was found within the string
/// </summary>
public readonly TimeSpan UtcOffset;
/// <summary>
/// True if UTC offset was found in the string
/// </summary>
public readonly bool IsUtcOffsetFound;
/// <summary>
/// Utc gotten from DateTime if IsUtcOffsetFound is True
/// </summary>
public DateTime UtcDateTime;
internal ParsedDateTime(int indexOfDate, int lengthOfDate, int indexOfTime, int lengthOfTime, DateTime dateTime)
{
IndexOfDate = indexOfDate;
LengthOfDate = lengthOfDate;
IndexOfTime = indexOfTime;
LengthOfTime = lengthOfTime;
DateTime = dateTime;
IsDateFound = indexOfDate > -1;
IsTimeFound = indexOfTime > -1;
UtcOffset = new TimeSpan(25, 0, 0);
IsUtcOffsetFound = false;
UtcDateTime = new DateTime(1, 1, 1);
}
internal ParsedDateTime(int indexOfDate, int lengthOfDate, int indexOfTime, int lengthOfTime, DateTime dateTime, TimeSpan utcOffset)
{
IndexOfDate = indexOfDate;
LengthOfDate = lengthOfDate;
IndexOfTime = indexOfTime;
LengthOfTime = lengthOfTime;
DateTime = dateTime;
IsDateFound = indexOfDate > -1;
IsTimeFound = indexOfTime > -1;
UtcOffset = utcOffset;
IsUtcOffsetFound = Math.Abs(utcOffset.TotalHours) < 12;
if (!IsUtcOffsetFound)
UtcDateTime = new DateTime(1, 1, 1);
else
{
if (indexOfDate < 0)//to avoid negative date exception when date is undefined
{
var ts = dateTime.TimeOfDay + utcOffset;
if (ts < new TimeSpan(0))
UtcDateTime = new DateTime(1, 1, 2) + ts;
else
UtcDateTime = new DateTime(1, 1, 1) + ts;
}
else
UtcDateTime = dateTime + utcOffset;
}
}
}
/// <summary>
/// Date that is accepted in the following cases:
/// - no date was parsed by TryParseDateOrTime();
/// - no year was found by TryParseDate();
/// It is ignored if DefaultDateIsNow = true was set after DefaultDate
/// </summary>
public static DateTime DefaultDate
{
set
{
_DefaultDate = value;
DefaultDateIsNow = false;
}
get => DefaultDateIsNow ? DateTime.Now : _DefaultDate;
}
private static DateTime _DefaultDate = DateTime.Now;
/// <summary>
/// If true then DefaultDate property is ignored and DefaultDate is always DateTime.Now
/// </summary>
public static bool DefaultDateIsNow = true;
/// <summary>
/// Defines default date-time format.
/// </summary>
[Flags]
public enum DateTimeFormat
{
/// <summary>
/// month number goes before day number
/// </summary>
UsaDate,
/// <summary>
/// day number goes before month number
/// </summary>
UkDate,
///// <summary>
///// time is specifed through AM or PM
///// </summary>
//USA_TIME,
}
#endregion
#region parsing derived methods for DateTime output
/// <summary>
/// Tries to find date and time within the passed string and return it as DateTime structure.
/// </summary>
/// <param name="str">string that contains date and/or time</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="dateTime">parsed date-time output</param>
/// <returns>true if both date and time were found, else false</returns>
public static bool TryParseDateTime(this string str, DateTimeFormat defaultFormat, out DateTime dateTime)
{
if (!TryParseDateTime(str, defaultFormat, out ParsedDateTime parsedDateTime))
{
dateTime = new DateTime(1, 1, 1);
return false;
}
dateTime = parsedDateTime.DateTime;
return true;
}
/// <summary>
/// Tries to find date and/or time within the passed string and return it as DateTime structure.
/// If only date was found, time in the returned DateTime is always 0:0:0.
/// If only time was found, date in the returned DateTime is DefaultDate.
/// </summary>
/// <param name="str">string that contains date and(or) time</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="dateTime">parsed date-time output</param>
/// <returns>true if date and/or time was found, else false</returns>
public static bool TryParseDateOrTime(this string str, DateTimeFormat defaultFormat, out DateTime dateTime)
{
if (!TryParseDateOrTime(str, defaultFormat, out ParsedDateTime parsedDateTime))
{
dateTime = new DateTime(1, 1, 1);
return false;
}
dateTime = parsedDateTime.DateTime;
return true;
}
/// <summary>
/// Tries to find time within the passed string and return it as DateTime structure.
/// It recognizes only time while ignoring date, so date in the returned DateTime is always 1/1/1.
/// </summary>
/// <param name="str">string that contains time</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="time">parsed time output</param>
/// <returns>true if time was found, else false</returns>
public static bool TryParseTime(this string str, DateTimeFormat defaultFormat, out DateTime time)
{
if (!TryParseTime(str, defaultFormat, out var parsedTime, null))
{
time = new DateTime(1, 1, 1);
return false;
}
time = parsedTime.DateTime;
return true;
}
/// <summary>
/// Tries to find date within the passed string and return it as DateTime structure.
/// It recognizes only date while ignoring time, so time in the returned DateTime is always 0:0:0.
/// If year of the date was not found then it accepts the current year.
/// </summary>
/// <param name="str">string that contains date</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="date">parsed date output</param>
/// <returns>true if date was found, else false</returns>
public static bool TryParseDate(this string str, DateTimeFormat defaultFormat, out DateTime date)
{
if (!TryParseDate(str, defaultFormat, out ParsedDateTime parsedDate))
{
date = new DateTime(1, 1, 1);
return false;
}
date = parsedDate.DateTime;
return true;
}
#endregion
#region parsing derived methods for ParsedDateTime output
/// <summary>
/// Tries to find date and time within the passed string and return it as ParsedDateTime object.
/// </summary>
/// <param name="str">string that contains date-time</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="parsedDateTime">parsed date-time output</param>
/// <returns>true if both date and time were found, else false</returns>
public static bool TryParseDateTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedDateTime)
{
if (TryParseDateOrTime(str, defaultFormat, out parsedDateTime)
&& parsedDateTime.IsDateFound
&& parsedDateTime.IsTimeFound
)
return true;
parsedDateTime = null;
return false;
}
/// <summary>
/// Tries to find time within the passed string and return it as ParsedDateTime object.
/// It recognizes only time while ignoring date, so date in the returned ParsedDateTime is always 1/1/1
/// </summary>
/// <param name="str">string that contains date-time</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="parsedTime">parsed date-time output</param>
/// <returns>true if time was found, else false</returns>
public static bool TryParseTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedTime)
=> TryParseTime(str, defaultFormat, out parsedTime, null);
/// <summary>
/// Tries to find date and/or time within the passed string and return it as ParsedDateTime object.
/// If only date was found, time in the returned ParsedDateTime is always 0:0:0.
/// If only time was found, date in the returned ParsedDateTime is DefaultDate.
/// </summary>
/// <param name="str">string that contains date-time</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="parsedDateTime">parsed date-time output</param>
/// <returns>true if date or time was found, else false</returns>
public static bool TryParseDateOrTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedDateTime)
{
parsedDateTime = null;
ParsedDateTime parsedTime;
if (!TryParseDate(str, defaultFormat, out
ParsedDateTime parsedDate))
{
if (!TryParseTime(str, defaultFormat, out parsedTime, null))
return false;
var dateTime = new DateTime(DefaultDate.Year, DefaultDate.Month, DefaultDate.Day, parsedTime.DateTime.Hour, parsedTime.DateTime.Minute, parsedTime.DateTime.Second);
parsedDateTime = new ParsedDateTime(-1, -1, parsedTime.IndexOfTime, parsedTime.LengthOfTime, dateTime, parsedTime.UtcOffset);
}
else
{
if (!TryParseTime(str, defaultFormat, out parsedTime, parsedDate))
{
var dateTime = new DateTime(parsedDate.DateTime.Year, parsedDate.DateTime.Month, parsedDate.DateTime.Day, 0, 0, 0);
parsedDateTime = new ParsedDateTime(parsedDate.IndexOfDate, parsedDate.LengthOfDate, -1, -1, dateTime);
}
else
{
var dateTime = new DateTime(parsedDate.DateTime.Year, parsedDate.DateTime.Month, parsedDate.DateTime.Day, parsedTime.DateTime.Hour, parsedTime.DateTime.Minute, parsedTime.DateTime.Second);
parsedDateTime = new ParsedDateTime(parsedDate.IndexOfDate, parsedDate.LengthOfDate, parsedTime.IndexOfTime, parsedTime.LengthOfTime, dateTime, parsedTime.UtcOffset);
}
}
return true;
}
#endregion
#region parsing base methods
/// <summary>
/// Tries to find time within the passed string (relatively to the passed parsed_date if any) and return it as ParsedDateTime object.
/// It recognizes only time while ignoring date, so date in the returned ParsedDateTime is always 1/1/1
/// </summary>
/// <param name="str">string that contains date</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="parsedTime">parsed date-time output</param>
/// <param name="parsedDate">ParsedDateTime object if the date was found within this string, else NULL</param>
/// <returns>true if time was found, else false</returns>
public static bool TryParseTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedTime, ParsedDateTime parsedDate)
{
parsedTime = null;
var timeZoneR = defaultFormat == DateTimeFormat.UsaDate ?
@"(?:\s*(?'time_zone'UTC|GMT|CST|EST))?" : @"(?:\s*(?'time_zone'UTC|GMT))?";
Match m;
if (parsedDate != null && parsedDate.IndexOfDate > -1)
{//look around the found date
//look for <date> hh:mm:ss <UTC offset>
m = Regex.Match(str.Substring(parsedDate.IndexOfDate + parsedDate.LengthOfDate), @"(?<=^\s*,?\s+|^\s*at\s*|^\s*[T\-]\s*)(?'hour'\d{2})\s*:\s*(?'minute'\d{2})\s*:\s*(?'second'\d{2})\s+(?'offset_sign'[\+\-])(?'offset_hh'\d{2}):?(?'offset_mm'\d{2})(?=$|[^\d\w])", RegexOptions.Compiled);
if (!m.Success)
//look for <date> [h]h:mm[:ss] [PM/AM] [UTC/GMT]
m = Regex.Match(str.Substring(parsedDate.IndexOfDate + parsedDate.LengthOfDate), @"(?<=^\s*,?\s+|^\s*at\s*|^\s*[T\-]\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + timeZoneR + @"(?=$|[^\d\w])", RegexOptions.Compiled);
if (!m.Success)
//look for [h]h:mm:ss [PM/AM] [UTC/GMT] <date>
m = Regex.Match(str.Substring(0, parsedDate.IndexOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + timeZoneR + @"(?=$|[\s,]+)", RegexOptions.Compiled);
if (!m.Success)
//look for [h]h:mm:ss [PM/AM] [UTC/GMT] within <date>
m = Regex.Match(str.Substring(parsedDate.IndexOfDate, parsedDate.LengthOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + timeZoneR + @"(?=$|[\s,]+)", RegexOptions.Compiled);
}
else//look anywhere within string
{
//look for hh:mm:ss <UTC offset>
m = Regex.Match(str, @"(?<=^|\s+|\s*T\s*)(?'hour'\d{2})\s*:\s*(?'minute'\d{2})\s*:\s*(?'second'\d{2})\s+(?'offset_sign'[\+\-])(?'offset_hh'\d{2}):?(?'offset_mm'\d{2})?(?=$|[^\d\w])", RegexOptions.Compiled);
if (!m.Success)
//look for [h]h:mm[:ss] [PM/AM] [UTC/GMT]
m = Regex.Match(str, @"(?<=^|\s+|\s*T\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + timeZoneR + @"(?=$|[^\d\w])", RegexOptions.Compiled);
}
if (!m.Success)
return false;
//try
//{
var hour = int.Parse(m.Groups["hour"].Value);
if (hour < 0 || hour > 23)
return false;
var minute = int.Parse(m.Groups["minute"].Value);
if (minute < 0 || minute > 59)
return false;
var second = 0;
if (!string.IsNullOrEmpty(m.Groups["second"].Value))
{
second = int.Parse(m.Groups["second"].Value);
if (second < 0 || second > 59)
return false;
}
if ("PM".Equals(m.Groups["ampm"].Value, StringComparison.OrdinalIgnoreCase) && hour < 12)
hour += 12;
else if ("AM".Equals(m.Groups["ampm"].Value, StringComparison.OrdinalIgnoreCase) && hour == 12)
hour -= 12;
var dateTime = new DateTime(1, 1, 1, hour, minute, second);
if (m.Groups["offset_hh"].Success)
{
var offsetHh = int.Parse(m.Groups["offset_hh"].Value);
var offsetMm = 0;
if (m.Groups["offset_mm"].Success)
offsetMm = int.Parse(m.Groups["offset_mm"].Value);
var utcOffset = new TimeSpan(offsetHh, offsetMm, 0);
if (m.Groups["offset_sign"].Value == "-")
utcOffset = -utcOffset;
parsedTime = new ParsedDateTime(-1, -1, m.Index, m.Length, dateTime, utcOffset);
return true;
}
if (m.Groups["time_zone"].Success)
{
TimeSpan utcOffset;
switch (m.Groups["time_zone"].Value)
{
case "UTC":
case "GMT":
utcOffset = new TimeSpan(0, 0, 0);
break;
case "CST":
utcOffset = new TimeSpan(-6, 0, 0);
break;
case "EST":
utcOffset = new TimeSpan(-5, 0, 0);
break;
default:
throw new Exception("Time zone: " + m.Groups["time_zone"].Value + " is not defined.");
}
parsedTime = new ParsedDateTime(-1, -1, m.Index, m.Length, dateTime, utcOffset);
return true;
}
parsedTime = new ParsedDateTime(-1, -1, m.Index, m.Length, dateTime);
//}
//catch(Exception e)
//{
// return false;
//}
return true;
}
/// <summary>
/// Tries to find date within the passed string and return it as ParsedDateTime object.
/// It recognizes only date while ignoring time, so time in the returned ParsedDateTime is always 0:0:0.
/// If year of the date was not found then it accepts the current year.
/// </summary>
/// <param name="str">string that contains date</param>
/// <param name="defaultFormat">format to be used preferably in ambivalent instances</param>
/// <param name="parsedDate">parsed date output</param>
/// <returns>true if date was found, else false</returns>
public static bool TryParseDate(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedDate)
{
parsedDate = null;
if (string.IsNullOrEmpty(str))
return false;
//look for dd/mm/yy
var m = Regex.Match(str, @"(?<=^|[^\d])(?'day'\d{1,2})\s*(?'separator'[\\/\.])+\s*(?'month'\d{1,2})\s*\'separator'+\s*(?'year'\d{2}|\d{4})(?=$|[^\d])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (m.Success)
{
DateTime date;
if ((defaultFormat ^ DateTimeFormat.UsaDate) == DateTimeFormat.UsaDate)
{
if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["day"].Value), int.Parse(m.Groups["month"].Value), out date))
return false;
}
else
{
if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out date))
return false;
}
parsedDate = new ParsedDateTime(m.Index, m.Length, -1, -1, date);
return true;
}
//look for [yy]yy-mm-dd
m = Regex.Match(str, @"(?<=^|[^\d])(?'year'\d{2}|\d{4})\s*(?'separator'[\-])\s*(?'month'\d{1,2})\s*\'separator'+\s*(?'day'\d{1,2})(?=$|[^\d])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (m.Success)
{
if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out var date))
return false;
parsedDate = new ParsedDateTime(m.Index, m.Length, -1, -1, date);
return true;
}
//look for month dd yyyy
m = Regex.Match(str, @"(?:^|[^\d\w])(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?\s*,?\s*(?'year'\d{4})(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (!m.Success)
//look for dd month [yy]yy
m = Regex.Match(str, @"(?:^|[^\d\w:])(?'day'\d{1,2})(?:-?st\s+|-?th\s+|-?rd\s+|-?nd\s+|-|\s+)(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*(?:\s*,?\s*|-)'?(?'year'\d{2}|\d{4})(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (!m.Success)
//look for yyyy month dd
m = Regex.Match(str, @"(?:^|[^\d\w])(?'year'\d{4})\s+(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (!m.Success)
//look for month dd hh:mm:ss MDT|UTC yyyy
m = Regex.Match(str, @"(?:^|[^\d\w])(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})\s+\d{2}\:\d{2}\:\d{2}\s+(?:MDT|UTC)\s+(?'year'\d{4})(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (!m.Success)
//look for month dd [yyyy]
m = Regex.Match(str, @"(?:^|[^\d\w])(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?(?:\s*,?\s*(?'year'\d{4}))?(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (m.Success)
{
var month = -1;
var indexOfDate = m.Index;
var lengthOfDate = m.Length;
switch (m.Groups["month"].Value)
{
case "Jan":
case "JAN":
month = 1;
break;
case "Feb":
case "FEB":
month = 2;
break;
case "Mar":
case "MAR":
month = 3;
break;
case "Apr":
case "APR":
month = 4;
break;
case "May":
case "MAY":
month = 5;
break;
case "Jun":
case "JUN":
month = 6;
break;
case "Jul":
month = 7;
break;
case "Aug":
case "AUG":
month = 8;
break;
case "Sep":
case "SEP":
month = 9;
break;
case "Oct":
case "OCT":
month = 10;
break;
case "Nov":
case "NOV":
month = 11;
break;
case "Dec":
case "DEC":
month = 12;
break;
}
var year = !string.IsNullOrEmpty(m.Groups["year"].Value) ?
int.Parse(m.Groups["year"].Value) : DefaultDate.Year;
if (!ConvertToDate(year, month, int.Parse(m.Groups["day"].Value), out var date))
return false;
parsedDate = new ParsedDateTime(indexOfDate, lengthOfDate, -1, -1, date);
return true;
}
return false;
}
private static bool ConvertToDate(int year, int month, int day, out DateTime date)
{
if (year >= 100)
{
if (year < 1000)
{
date = new DateTime(1, 1, 1);
return false;
}
}
else
if (year > 30)
year += 1900;
else
year += 2000;
try
{
date = new DateTime(year, month, day);
}
catch
{
date = new DateTime(1, 1, 1);
return false;
}
return true;
}
#endregion
}
}

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8</LangVersion>
<NoWarn />
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
</PropertyGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1 +0,0 @@
span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container>li{padding:0}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;padding:3px 20px 3px 20px;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>a{padding:0}.multiselect-container>li>a>label{margin:0;height:100%;cursor:pointer;font-weight:400;padding:3px 20px 3px 40px}.multiselect-container>li>a>label.radio,.multiselect-container>li>a>label.checkbox{margin:0}.multiselect-container>li>a>label>input[type=checkbox]{margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container label.checkbox,.form-inline .multiselect-container label.radio{padding:3px 20px 3px 40px}.form-inline .multiselect-container li a label.checkbox input[type=checkbox],.form-inline .multiselect-container li a label.radio input[type=radio]{margin-left:-20px;margin-right:0}

File diff suppressed because one or more lines are too long

View File

@@ -1,326 +0,0 @@
body {
background-image: url("binding_dark.png");
background-repeat: repeat;
}
#page {
border-radius: 6px;
background-color: white;
max-width: 900px;
padding: 20px;
margin: 30px auto 100px;
}
.container-fluid {
}
#templates {
display: none;
}
#indexers {
text-align: center;
margin-top: 20px;
}
.indexer-table {
text-align: left;
}
.test-success {
color: #449d44;
}
.test-error {
color: #c9302c;
}
.test-inprogress {
color: #286090;
}
.indexer-buttons {
text-align: center;
}
.indexer-buttons > .btn {
margin-bottom: 2px;
}
.indexer-button-test {
width: 60px;
}
.setup-item-inputstring {
max-width: 255px;
}
.setup-item-inputcheckbox label {
padding: 0 1.5em;
}
.setup-item-inputcheckbox input {
height: 20px;
}
.setup-item-inputbool input {
max-width: 100px;
height: 20px;
}
.setup-item-inputselect {
max-width: 255px;
}
[data-type=hiddendata]{
display: none;
}
.spinner {
-webkit-animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
@-moz-keyframes spin {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#setup-indexer-go {
width: 70px;
}
hr {
border-top-color: #cdcdcd;
}
.input-area {
margin: 4px 0;
}
.input-area > * {
vertical-align: middle;
}
.input-area > p {
margin-top: 10px;
}
.input-header {
font-size: 18px;
width: 160px;
display: inline-block;
}
.input-right {
width: 300px;
display: inline-block;
font-family: monospace;
}
#sonarr-warning {
display: none;
}
#logo {
max-width: 50px;
}
#header-title {
font-size: 34px;
vertical-align: middle;
padding-left: 15px;
}
#footer {
color: #444444;
margin: 10px auto 0;
text-align: center;
}
#jackett-allowext, #jackett-allowupdate, #jackett-logging, #jackett-prerelease {
width: 25px;
}
.modal-fillwidth {
width: 1200px;
min-width:80%;
}
.indexer-caps {
padding: 0 15px 15px 15px;
border-top: 1px solid #e5e5e5;
}
.indexer-caps table {
border-bottom: 1px solid #ddd;
}
.jackettlog-narrowcol {
width: 1px;
white-space: nowrap;
vertical-align: top;
}
.jackettlogWarn {
background-color: #FFFF8E !important;
}
.jackettlogError {
background-color: #FF6060 !important;
}
.jackettdownloaded {
color: blueviolet;
}
.jacketdownloadlocal {
padding-left: 10px;
}
.downloadcolumn {
text-align:center;
}
pre {
display: block;
padding: 3px;
margin: 0 0 0;
font-size: 13px;
line-height: 1.42857143;
color: #333;
background-color: transparent;
border: 0;
border-radius: 0;
word-break: normal;
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.modal-open .modal {
overflow-x: auto; /* Model can be bigger than the screen on mobiles */
}
.dataTables_length {
white-space: nowrap;
}
.dataTables_length select, .dataTables_filter input, .dataTable.compact tfoot td select {
display: inline-block;
height: 26px;
padding: 0 8px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
}
.dataTables_length select {
width: inherit;
}
.dataTables_filter input {
width: 400px;
}
.dataTable.compact tfoot td {
padding: 4px 0;
}
.dataTable.compact tfoot td select {
height: 26px;
padding: 0;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
padding: 3px 9px !important;
}
#unconfigured-indexers-template {
display: none;
}
.jackett-apikey{
margin-top: 10px;
}
.jackett-apikey .input-header{
width: 80px;
}
.setup-item-displayinfo:empty {
display: none;
}
table td.fit{
white-space: nowrap;
width: 1%;
}
.label-imdb {
background-color: #d0ab44;
}
.tooltip-inner {
max-width: 500px !important;
}
.tooltip-inner img {
max-width: 250px;
height: auto;
}
.type-public {
color: #449d44
}
.type-private {
color: #c9302c
}
.type-semi-private {
color: #ec971f
}
.dataTables_deadfilter {
float: right;
text-align: right;
margin-right: 1em;
}
input#searchquery {
width: 400px;
display: inline-block;
}
#proxy-warning {
color: red;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,328 +0,0 @@
body {
background-image: url("binding_dark.png");
background-repeat: repeat;
}
#page {
border-radius: 6px;
background-color: white;
max-width: 900px;
padding: 20px;
margin: 30px auto;
}
.container-fluid {
}
#templates {
display: none;
}
#indexers {
text-align: center;
margin-top: 20px;
}
.indexer-table {
text-align: left;
}
.test-success {
color: #449d44;
}
.test-error {
color: #c9302c;
}
.test-inprogress {
color: #286090;
}
.indexer-buttons {
text-align: center;
}
.indexer-buttons > .btn {
margin-bottom: 2px;
}
.indexer-button-test {
width: 60px;
}
.setup-item-inputstring {
max-width: 255px;
}
.setup-item-inputbool input {
max-width: 100px;
height: 20px;
}
.setup-item-inputselect {
max-width: 255px;
}
[data-type=hiddendata]{
display: none;
}
.spinner {
-webkit-animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
@-moz-keyframes spin {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#setup-indexer-go {
width: 70px;
}
hr {
border-top-color: #cdcdcd;
}
.input-area {
margin: 4px 0;
}
.input-area > * {
vertical-align: middle;
}
.input-area > p {
margin-top: 10px;
}
.input-header {
font-size: 18px;
width: 160px;
display: inline-block;
}
.input-right {
width: 300px;
display: inline-block;
font-family: monospace;
}
#sonarr-warning {
display: none;
}
#logo {
max-width: 50px;
}
#header-title {
font-size: 34px;
vertical-align: middle;
padding-left: 15px;
}
#footer {
color: #444444;
margin: 10px auto 0;
text-align: center;
}
#jackett-allowext, #jackett-allowupdate, #jackett-logging, #jackett-prerelease {
width: 25px;
}
.modal-fillwidth {
width: 100%;
min-width:80%;
}
.indexer-caps {
padding: 0 15px 15px 15px;
border-top: 1px solid #e5e5e5;
}
.indexer-caps table {
border-bottom: 1px solid #ddd;
}
.jackettlog-narrowcol {
width: 1px;
white-space: nowrap;
vertical-align: top;
}
.jackettlogWarn {
background-color: #FFFF8E !important;
}
.jackettlogError {
background-color: #FF6060 !important;
}
.jackettdownloaded {
color: blueviolet;
}
.jacketdownloadlocal {
padding-left: 10px;
}
.downloadcolumn {
text-align:center;
}
pre {
display: block;
padding: 3px;
margin: 0 0 0;
font-size: 13px;
line-height: 1.42857143;
color: #333;
background-color: transparent;
border: 0;
border-radius: 0;
word-break: normal;
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.modal-open .modal {
overflow-x: auto; /* Model can be bigger than the screen on mobiles */
}
.dataTables_length {
white-space: nowrap;
}
.dataTables_length select, .dataTables_filter input, .dataTable.compact tfoot td select {
display: inline-block;
height: 26px;
padding: 0 8px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
}
.dataTables_length select {
width: inherit;
}
.dataTables_filter input {
width: 75%;
}
.dataTable.compact tfoot td {
padding: 4px 0;
}
.dataTable.compact tfoot td select {
height: 26px;
padding: 0;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
padding: 3px 9px !important;
}
#unconfigured-indexers-template {
display: none;
}
.jackett-apikey{
margin-top: 10px;
}
.jackett-apikey .input-header{
width: 80px;
}
.setup-item-displayinfo:empty {
display: none;
}
table td.fit{
width: 50%;
}
.label-imdb {
background-color: #d0ab44;
}
.tooltip-inner {
max-width: 500px !important;
}
.tooltip-inner img {
max-width: 250px;
height: auto;
}
.type-public {
color: #449d44
}
.type-private {
color: #c9302c
}
.type-semi-private {
color: #ec971f
}
.dataTables_deadfilter {
float: right;
text-align: right;
margin-right: 1em;
}
div#jackett-search-results-datatable_wrapper {
width: 100%;
overflow-x: scroll;
}
div#unconfigured-indexer-datatable_wrapper {
width: 100%;
overflow-x: scroll;
}
div#jackett-releases-datatable_wrapper {
width: 100%;
overflow-x: scroll;
}
input#searchquery {
width: 50%;
display: inline-block;
}
#proxy-warning {
color: red;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -1,696 +0,0 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta charset="utf-8" />
<meta name="referrer" content="no-referrer" /> <!-- Don't send referrer when loading third party ressources (E.g. Empornium banner images won't load) -->
<link rel="apple-touch-icon" href="../apple-touch-icon.png" />
<link rel="apple-touch-icon" sizes="57x57" href="../apple-touch-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="72x72" href="../apple-touch-icon-72x72.png" />
<link rel="apple-touch-icon" sizes="76x76" href="../apple-touch-icon-76x76.png" />
<link rel="apple-touch-icon" sizes="114x114" href="../apple-touch-icon-114x114.png" />
<link rel="apple-touch-icon" sizes="120x120" href="../apple-touch-icon-120x120.png" />
<link rel="apple-touch-icon" sizes="144x144" href="../apple-touch-icon-144x144.png" />
<link rel="apple-touch-icon" sizes="152x152" href="../apple-touch-icon-152x152.png" />
<link rel="apple-touch-icon" sizes="180x180" href="../apple-touch-icon-180x180.png" />
<link rel="mask-icon" href="../jackett_medium.png" color="#35c5f4">
<link rel="icon" type="image/ico" href="../favicon.ico" />
<link rel='shortcut icon' type='image/x-icon' href='../favicon.ico' />
<script type="text/javascript" src="../libs/filesize.min.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/jquery.min.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/jquery.dataTables.min.js?changed=2017083001" charset="utf8"></script>
<script type="text/javascript" src="../libs/handlebars.min.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/moment.min.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/handlebarsmoment.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/handlebarsextend.js?changed=2017083001"></script>
<script type="text/javascript" src="../bootstrap/bootstrap.min.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/bootstrap-notify.js?changed=2017083001"></script>
<script type="text/javascript" src="../libs/bootstrap-multiselect.js?changed=2017083001"></script>
<!--<script type="text/javascript" src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>-->
<link rel="stylesheet" type="text/css" href="../bootstrap/bootstrap.min.css?changed=2017083001">
<link rel="stylesheet" type="text/css" href="../animate.css?changed=2017083001">
<link rel="stylesheet" type="text/css" href="../custom.css?changed=20200223" media="only screen and (min-device-width: 480px)">
<link rel="stylesheet" type="text/css" href="../custom_mobile.css?changed=20200223" media="only screen and (max-device-width: 480px)">
<link rel="stylesheet" type="text/css" href="../css/jquery.dataTables.min.css?changed=2017083001">
<link rel="stylesheet" type="text/css" href="../css/bootstrap-multiselect.css?changed=2017083001" />
<link rel="stylesheet" type="text/css" href="../css/font-awesome.min.css?changed=2017083001">
<title>Jackett</title>
</head>
<body>
<div id="page">
<img id="logo" src="../jacket_medium.png" alt="Logo" /><span id="header-title">Jackett</span>
<div class="pull-right jackett-apikey">
<span class="input-header">API Key: </span>
<input id="api-key-input" class="form-control input-right" type="text" value="" placeholder="API Key" readonly="">
</div>
<hr />
<div id="can-upgrade-from-mono" hidden class="alert alert-info" role="alert">
<strong>Standalone version of Jackett is now available - Mono not required</strong> <br>
To upgrade to the standalone version of Jackett, <a href="https://github.com/Jackett/Jackett#install-on-linux-amdx64" target="_blank" class="alert-link">click here</a> for install instructions.
Upgrading is straight forward, simply install the standalone version and your indexers/configuration will carry over.
Benefits include: increased performance, improved stability and no dependency on Mono.
</div>
<div class="pull-right">
<button id="jackett-add-indexer" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add indexer
</button>
<button id="jackett-show-search" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span> Manual Search
</button>
<button id="jackett-show-releases" class="btn btn-primary btn-sm">
<i class="fa fa-database"></i> View cached releases
</button>
<button id="jackett-test-all" class="btn btn-warning btn-sm">
<span class="glyphicon glyphicon-screenshot" aria-hidden="true"></span> Test All
</button>
</div>
<h3>Configured Indexers</h3>
<div id="indexers"> </div>
<hr />
<div class="input-area">
<h4>Adding a Jackett indexer in Sonarr or Radarr</h4>
<ol>
<li>Go to <b>Settings > Indexers > Add > Torznab > Custom</b>.</li>
<li>Click on the indexers corresponding <button type="button" class="btn btn-xs btn-info">Copy Torznab Feed</button> button and paste it into the Sonarr/Radarr <b>URL</b> field.</li>
<li>For the <b>API key</b> use <b class="api-key-text"></b>.</li>
<li>Configure the correct category IDs via the <b>(Anime) Categories</b> options. See the Jackett indexer configuration for a list of supported categories.</li>
</ol>
<h4>Adding a Jackett indexer in CouchPotato</h4>
<ol>
<li>Go to <b>Settings > Searchers</b>.</li>
<li>Enable <b>TorrentPotato</b>.
<li>Click on the indexers corresponding <button type="button" class="btn btn-xs btn-info">Copy Potato Feed</button> button and paste it into the CouchPotato <b>host</b> field.</li>
<li>For the <b>Passkey</b> use <b class="api-key-text"></b>. Leave the <b>username</b> field blank.</li>
</ol>
<h4>Adding a Jackett indexer to RSS clients (RSS feed)</h4>
<ol>
<li>Click on the indexers corresponding <button type="button" class="btn btn-xs btn-info">Copy RSS Feed</button> button and paste it into the URL field of the RSS client.</li>
<li>
You can adjust the <b>q</b> (search string) and <b>cat</b> (categories) arguments accordingly.
E.g. <b>...&cat=2030,2040&q=big+buck+bunny</b> will search for "big buck bunny" in the Movies/SD (2030) and Movies/HD (2040) categories (See the indexer configuration for available categories).
</li>
</ol>
</div>
<hr />
<h3>Jackett Configuration</h3>
<div class="text-center">
<div class="btn-toolbar">
<button id="change-jackett-port" class="btn btn-primary btn-sm">
<i class="fa fa-wrench"></i> Apply server settings <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button>
<button id="view-jackett-logs" class="btn btn-success btn-sm">
<i class="fa fa-rss"></i> View logs <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button>
<button id="trigger-updater" class="btn btn-warning btn-sm">
<i class="fa fa-wrench"></i> Check for updates <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button>
</div>
</div>
<br />
<div class="input-area">
<span class="input-header">Admin password: </span>
<input id="jackett-adminpwd" class="form-control input-right" type="password" value="" placeholder="Blank to disable" />
<button id="change-jackett-password" class="btn btn-primary btn-sm">
<i class="fa fa-user-secret"></i> Set Password <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button>
<a href="Dashboard?logout=true" id="logoutBtn" style="display:none" class="btn btn-danger btn-sm">
Logout
</a>
</div>
<div class="input-area">
<span class="input-header">Base Path Override: </span>
<input id="jackett-basepathoverride" class="form-control input-right" type="text" value="" placeholder="/jackett">
</div>
<div class="input-area">
<span class="input-header">Server port: </span>
<input id="jackett-port" class="form-control input-right" type="text" value="" placeholder="9117">
</div>
<div class="input-area">
<span class="input-header">Manual download blackhole directory: </span>
<input id="jackett-savedir" class="form-control input-right" type="text" value="" placeholder="c:\torrents\">
</div>
<div class="input-area">
<span class="input-header">Proxy type: </span>
<select id="jackett-proxy-type" class="form-control input-right">
<option value="0">http</option>
<option value="1">socks4</option>
<option value="2">socks5</option>
</select>
</div>
<div id="proxy-warning" hidden>
<span>
WARNING: The proxy option potentially leaks requests. Recommendation is to use a VPN.
</span>
</div>
<div class="input-area">
<span class="input-header">Proxy url: </span>
<input id="jackett-proxy-url" class="form-control input-right" type="text" value="" placeholder="Blank to disable">
</div>
<div class="input-area">
<span class="input-header">Proxy port: </span>
<input id="jackett-proxy-port" class="form-control input-right" type="text" value="" placeholder="">
</div>
<div class="input-area">
<span class="input-header">Proxy username: </span>
<input id="jackett-proxy-username" class="form-control input-right" type="text" value="" placeholder="">
</div>
<div class="input-area">
<span class="input-header">Proxy password: </span>
<input id="jackett-proxy-password" class="form-control input-right" type="password" value="" placeholder="">
</div>
<div class="input-area">
<span class="input-header">External access: </span>
<input id="jackett-allowext" class="form-control input-right" type="checkbox" />
</div>
<div class="input-area">
<span class="input-header">Disable auto update: </span>
<input id="jackett-allowupdate" class="form-control input-right" type="checkbox" />
</div>
<div class="input-area">
<span class="input-header">Update to pre-release: </span>
<input id="jackett-prerelease" class="form-control input-right" type="checkbox" />
</div>
<div class="input-area">
<span class="input-header">Enhanced logging: </span>
<input id="jackett-logging" class="form-control input-right" type="checkbox" />
</div>
<div class="input-area">
<span class="input-header">OMDB API key: </span>
<input id="jackett-omdbkey" class="form-control input-right" type="text" value="" placeholder="">
</div>
<div class="input-area">
<span class="input-header">OMDB API Url: </span>
<input id="jackett-omdburl" class="form-control input-right" type="text" value="" placeholder="Blank for default">
</div>
<hr />
<div id="footer">
<a href="https://github.com/Jackett/Jackett" target="_blank" title="Jackett on GitHub">Jackett</a> Version <span id="app-version"></span>
</div>
</div>
<div id="modals"></div>
<script id="setup-item-nonlocalrecaptcha" type="text/x-handlebars-template">
<div class="setup-item-recaptcha">
<p>This site requires you to solve a ReCaptcha. It's no longer possible to solve the captcha in Jackett. Please enter the cookie for the site manually. <a href="https://github.com/Jackett/Jackett/wiki/Finding-cookies" target="_blank">See here</a> on how get the cookies.</p>
<div class="setup-item-label">Full cookie header</div>
<input class="form-control" type="text" value="{{cookieheader}}" />
</div>
</script>
<script id="setup-item" type="text/x-handlebars-template">
<div class="setup-item form-group" data-id="{{id}}" data-value="{{value}}" data-type="{{type}}">
<div class="setup-item-label">{{name}}</div>
<div class="setup-item-value">{{{value_element}}}</div>
</div>
</script>
<script id="setup-item-inputstring" type="text/x-handlebars-template">
<div class="setup-item-inputstring">
{{#if ispassword}}
<input class="form-control" type="password" value="{{{value}}}" />
{{else}}
<input class="form-control" type="text" value="{{{value}}}" />
{{/if}}
</div>
</script>
<script id="setup-item-inputbool" type="text/x-handlebars-template">
<div class="setup-item-inputbool">
{{#if value}}
<input type="checkbox" data-id="{{id}}" class="form-control" checked />
{{else}}
<input type="checkbox" data-id="{{id}}" class="form-control" />
{{/if}}
</div>
</script>
<script id="setup-item-inputcheckbox" type="text/x-handlebars-template">
<div class="setup-item-inputcheckbox">
{{#each options}}
<div class="checkbox"><label>
{{#if_in @key ../values}}
<input type="checkbox" data-id="{{../../id}}" class="form-control" value="{{@key}}" checked />
{{else}}
<input type="checkbox" data-id="{{../../id}}" class="form-control" value="{{@key}}" />
{{/if_in}}
{{this}}</label></div>
{{/each}}
</div>
</script>
<script id="setup-item-inputselect" type="text/x-handlebars-template">
<div class="setup-item-inputselect">
<select class="form-control" data-id="{{id}}">
{{#each options}}
{{#ifCond ../value @key}}
<option value="{{@key}}" selected>{{this}}</option>
{{else}}
<option value="{{@key}}">{{this}}</option>
{{/ifCond}}
{{/each}}
</select>
</div>
</script>
<script id="setup-item-recaptcha" type="text/x-handlebars-template">
<div class="jackettrecaptcha">
</div>
</script>
<script id="setup-item-displayimage" type="text/x-handlebars-template">
<img class="setup-item-displayimage" src="{{{value}}}" alt="No image available" />
</script>
<script id="setup-item-displayinfo" type="text/x-handlebars-template">
<div class="setup-item-displayinfo alert alert-info" role="alert">{{{value}}}</div>
</script>
<script id="setup-item-hiddendata" type="text/x-handlebars-template">
<div class="setup-item-hiddendata">
<input class="form-control" type="text" value="{{{value}}}" />
</div>
</script>
<script id="setup-item-alternativesitelinks" type="text/x-handlebars-template">
<div class="setup-item-alternativesitelinks alert alert-info" role="alert">
This indexer has multiple known URLs:
<ul>
{{#each alternativesitelinks}}
<li><a target="_blank" href="{{this}}" class="alternativesitelink">{{this}}</a></li>
{{/each}}
</ul>
Click on an URL to copy it to the Site Link field.
</div>
</script>
<script id="configured-indexer-table" type="text/x-handlebars-template">
<div class="configured-indexer-div">
<table id="configured-indexer-datatable" class="indexer-table dataTable compact cell-border hover stripe table table-responsive">
<thead>
<tr>
<th>Indexer</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{#each indexers}}
<tr class="configured-indexer-row">
<td><a target="_blank" href="{{site_link}}" title="{{description}}">{{name}}</a> <span title="{{type}}" class="label label-{{type_label}}" style="text-transform: capitalize;">{{type}}</span></td>
<td class="fit">
<div class="indexer-buttons">
<a href="{{rss_host}}" title="{{rss_host}}" role="button" class="indexer-button-copy btn btn-xs btn-info">Copy RSS Feed</i></a>
<a href="{{torznab_host}}" title="{{torznab_host}}" role="button" class="indexer-button-copy btn btn-xs btn-info">Copy Torznab Feed</a>
<a href="{{potato_host}}" title="{{potato_host}}" role="button" class="indexer-button-copy btn btn-xs btn-info{{#unless potatoenabled}} disabled{{/unless}}">Copy Potato Feed</a>
<button title="Search" class="btn btn-success btn-xs indexer-button-search" data-id="{{id}}">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
<button title="Configure" class="btn btn-primary btn-xs indexer-setup" data-id="{{id}}" data-link="{{site_link}}">
<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
</button>
<button title="Delete" class="btn btn-danger btn-xs indexer-button-delete" data-id="{{id}}">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button>
<button title="{{last_error}}" class="btn btn-warning btn-xs indexer-button-test" data-toggle="tooltip" data-id="{{id}}" data-state="{{state}}">
Test
<span class="glyphicon" aria-hidden="true"></span>
</button>
</div>
</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="2"></td>
</tr>
</tfoot>
</table>
</div>
</script>
<script id="unconfigured-indexer-table" type="text/x-handlebars-template">
<div class="unconfigured-indexer-div">
<table id="unconfigured-indexer-datatable" class="indexer-table dataTable compact cell-border hover stripe table table-responsive">
<thead>
<tr>
<th>Indexer</th>
<th>Categories</th>
<th>Type</th>
<th>Type string</th>
<th>Language</th>
<th></th>
</tr>
</thead>
<tbody>
{{#each indexers}}
<tr class="unconfigured-indexer-row">
<td><a target="_blank" href="{{site_link}}" title="{{description}}">{{name}}</a></td>
<td>{{mains_cats}}</td>
<td class="fit"><span title="{{type}}" class="label label-{{type_label}}" style="text-transform: capitalize;">{{type}}</span></td>
<td>{{type}}</td>
<td class="fit">{{language}}</td>
<td class="fit">
<div class="indexer-buttons">
<button title="Configure" class="btn btn-primary btn-xs indexer-setup" data-id="{{id}}" data-link="{{site_link}}">
<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
</button>
{{#if_eq type "public"}}
<button title="Add" class="btn btn-success btn-xs indexer-add" data-id="{{id}}" data-link="{{site_link}}">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
</button>
{{/if_eq}}
</div>
</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="6"></td>
</tr>
</tfoot>
</table>
</div>
</script>
<script id="jackett-releases" type="text/x-handlebars-template">
<div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fillwidth">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Cached Releases</h4>
</div>
<div class="modal-body">
<p>This screen shows releases which have been recently returned from Jackett. Only the last 300 releases for each tracker are returned.</p>
<table id="jackett-releases-datatable" class="dataTable compact cell-border hover stripe">
<thead>
<tr>
<th>Published</th>
<th>First Seen</th>
<th>Published</th>
<th>First Seen</th>
<th>Tracker</th>
<th>Name</th>
<th>Size</th>
<th>Size</th>
<th>Files</th>
<th>Category</th>
<th>Grabs</th>
<th>Seeds</th>
<th>Leechers</th>
<th class="fit">DL Factor</th>
<th class="fit">UL Factor</th>
<th>Download</th>
</tr>
</thead>
<tbody>
{{#each releases}}
<tr class="jackett-releases-row" data-imdb="{{Imdb}}" data-banner="{{BannerUrl}}" data-description="{{Description}}">
<td class="fit">{{PublishDate}}</td>
<td class="fit">{{FirstSeen}}</td>
<td class="fit">{{jacketTimespan PublishDate}}</td>
<td class="fit">{{jacketTimespan FirstSeen}}</td>
<td class="fit">{{Tracker}}</td>
<td class="Title"><a href="{{Comments}}">{{Title}}</a> <span class="release-labels"></span></td>
<td class="fit">{{Size}}</td>
<td class="fit">{{jacketSize Size}}</td>
<td class="fit">{{Files}}</td>
<td class="fit">{{CategoryDesc}}</td>
<td class="fit">{{Grabs}}</td>
<td class="fit">{{Seeders}}</td>
<td class="fit">{{Peers}}</td>
<td class="fit DownloadVolumeFactor">{{DownloadVolumeFactor}}</td>
<td class="fit UploadVolumeFactor">{{UploadVolumeFactor}}</td>
<td class="fit downloadcolumn">
{{#if Link}}
<a class="downloadlink" title="Download locally" href="{{Link}}"><i class="fa fa-download"></i></a>
{{/if}}
{{#if MagnetUri}}
<a class="downloadlink" title="Download locally (magnet)" href="{{MagnetUri}}"><i class="fa fa-magnet"></i></a>
{{/if}}
{{#if BlackholeLink}}
<a class="downloadlink jacketdownloadserver" title="Save to server blackhole directory" href="{{BlackholeLink}}"><i class="fa fa-upload"></i></a>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</script>
<script id="jackett-search" type="text/x-handlebars-template">
<div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fillwidth">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Manual search</h4>
</div>
<div class="modal-body">
<p>You can search all configured indexers from this screen.</p>
<label for="text">Query</label>
<input class="form-control" type="text" name="query" id="searchquery" />
<label for="tracker">Tracker</label>
<select name="tracker" id="searchTracker" multiple="multiple">
{{#each indexers}}
<option value="{{id}}" selected>{{name}}</option>
{{/each}}
</select>
<label for="category">Category</label>
<select name="category" id="searchCategory" multiple="multiple"></select>
<button id="jackett-search-perform" class="btn btn-success btn-sm"><span class="fa fa-search"></span></button>
<div id="searchResults"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</script>
<script id="jackett-search-results" type="text/x-handlebars-template">
<hr />
<p>Your search was done using:
{{#each Indexers}}{{Name}}
{{#if Error}}
(<span title="{{Error}}"><b>Error</b></span>)
{{else}}
({{Results}})
{{/if}}
, {{/each}}
</p>
<table id="jackett-search-results-datatable" class="dataTable compact cell-border hover stripe">
<thead>
<tr>
<th>Published</th>
<th>Published</th>
<th>Tracker</th>
<th>Name</th>
<th>Size</th>
<th>Size</th>
<th>Files</th>
<th>Category</th>
<th>Grabs</th>
<th>Seeds</th>
<th>Leechers</th>
<th>DL Factor</th>
<th>UL Factor</th>
<th>Download</th>
</tr>
</thead>
<tbody>
{{#each Results}}
<tr class="jackett-search-results-row" data-imdb="{{Imdb}}" data-banner="{{BannerUrl}}" data-description="{{Description}}">
<td>{{PublishDate}}</td>
<td>{{jacketTimespan PublishDate}}</td>
<td>{{Tracker}}</td>
<td class="Title"><a href="{{Comments}}" target="_blank">{{Title}}</a> <span class="release-labels"></span></td>
<td>{{Size}}</td>
<td class="fit">{{jacketSize Size}}</td>
<td>{{Files}}</td>
<td>{{CategoryDesc}}</td>
<td>{{Grabs}}</td>
<td>{{Seeders}}</td>
<td>{{Peers}}</td>
<td class="DownloadVolumeFactor">{{DownloadVolumeFactor}}</td>
<td class="UploadVolumeFactor">{{UploadVolumeFactor}}</td>
<td class="downloadcolumn">
{{#if Link}}
<a class="downloadlink" title="Download locally" href="{{Link}}"><i class="fa fa-download"></i></a>
{{/if}}
{{#if MagnetUri}}
<a class="downloadlink" title="Download locally (magnet)" href="{{MagnetUri}}"><i class="fa fa-magnet"></i></a>
{{/if}}
{{#if BlackholeLink}}
<a class="downloadlink jacketdownloadserver" title="Save to server blackhole directory" href="{{BlackholeLink}}"><i class="fa fa-upload"></i></a>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
</script>
<script id="select-indexer" type="text/x-handlebars-template">
<div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Select an indexer to setup</h4>
</div>
<div class="modal-body">
<div id="unconfigured-indexers">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</script>
<script id="jackett-logs" type="text/x-handlebars-template">
<div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fillwidth">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Server Logs</h4>
</div>
<div class="modal-body">
<table class="dataTable compact cell-border hover stripe">
<thead>
<tr>
<th>Date</th>
<th>Level</th>
<th>Message</th>
</tr>
</thead>
<tbody>
{{#each logs}}
<tr class="jackettlog{{Level}}">
<td class="jackettlog-narrowcol">{{dateFormat When}}</td>
<td class="jackettlog-narrowcol">{{Level}}</td>
<td><pre>{{Message}}</pre></td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</script>
<script id="jackett-config-setup-modal" type="text/x-handlebars-template">
<div class="config-setup-modal modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">{{title}} - <a target="_blank" href="{{link}}">{{link}}</a></h4>
{{#if description}}
<div class="alert alert-info">{{description}}</div>
{{/if}}
</div>
<div class="modal-body">
<form class="config-setup-form"></form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary setup-indexer-go">Okay</button>
</div>
<div class="indexer-caps">
<h4>Capabilities</h4>
<table class="dataTable compact cell-border hover stripe">
<thead>
<tr>
<th>Category</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{{#each caps}}
<tr>
<td>{{ID}}</td>
<td>{{Name}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
</div>
</div>
</script>
<script id="spinner" type="text/x-handlebars-template">
<span class="spinner glyphicon glyphicon-refresh"></span>
</script>
<script id="search-button-ready" type="text/x-handlebars-template">
<span class="fa fa-search"></span>
</script>
<script type="text/javascript" src="../libs/api.js?changed=2017083001"></script>
<script type="text/javascript" src="../custom.js?changed=20200316"></script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,89 +0,0 @@
var api = {
version: "2.0",
root: "/api",
key: "",
getApiPath: function(category, action) {
var path = this.root + "/v" + this.version + "/" + category;
if (action !== undefined)
path = path + "/" + action
return path;
},
getAllIndexers: function(callback) {
return $.get(this.getApiPath("indexers"), callback);
},
getServerConfig: function(callback) {
return $.get(this.getApiPath("server", "config"), callback);
},
getIndexerConfig: function(indexerId, callback) {
return $.get(this.getApiPath("indexers", indexerId + "/config"), callback);
},
updateIndexerConfig: function(indexerId, config, callback) {
return $.ajax({
url: this.getApiPath("indexers", indexerId + "/config"),
type: 'POST',
data: JSON.stringify(config),
dataType: 'json',
contentType: 'application/json',
cache: false,
success: callback
});
},
deleteIndexer: function(indexerId, callback) {
return $.ajax({
url: this.getApiPath("indexers", indexerId),
type: 'DELETE',
cache: false,
success: callback
});
},
testIndexer: function(indexerId, callback) {
return $.post(this.getApiPath("indexers", indexerId + "/test"), callback);
},
resultsForIndexer: function(indexerId, query, callback) {
return $.get(this.getApiPath("indexers", indexerId + "/results?apikey=" + this.key), query, callback);
},
getServerCache: function(callback) {
return $.get(this.getApiPath("indexers", "cache"), callback);
},
getServerLogs: function(callback) {
return $.get(this.getApiPath("server", "logs"), callback);
},
updateServerConfig: function(serverConfig, callback) {
return $.ajax({
url: this.getApiPath("server", "config"),
type: 'POST',
data: JSON.stringify(serverConfig),
dataType: 'json',
contentType: 'application/json',
cache: false,
success: callback
});
},
updateServer: function(callback) {
return $.post(this.getApiPath("server", "update"), callback);
},
updateAdminPassword: function(password, callback) {
return $.ajax({
url: this.getApiPath("server", "adminpassword"),
type: 'POST',
data: JSON.stringify(password),
dataType: 'json',
contentType: 'application/json',
cache: false,
success: callback
});
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
/*
2015 Jason Mulligan
@version 3.1.2
*/
"use strict"; !function (a) { var b = /b$/, c = { bits: ["B", "kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb"], bytes: ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] }, d = function (a) { var d = void 0 === arguments[1] ? {} : arguments[1], e = [], f = !1, g = 0, h = void 0, i = void 0, j = void 0, k = void 0, l = void 0, m = void 0, n = void 0, o = void 0, p = void 0, q = void 0, r = void 0; if (isNaN(a)) throw new Error("Invalid arguments"); return j = d.bits === !0, p = d.unix === !0, i = void 0 !== d.base ? d.base : 2, o = void 0 !== d.round ? d.round : p ? 1 : 2, q = void 0 !== d.spacer ? d.spacer : p ? "" : " ", r = void 0 !== d.suffixes ? d.suffixes : {}, n = void 0 !== d.output ? d.output : "string", h = void 0 !== d.exponent ? d.exponent : -1, m = Number(a), l = 0 > m, k = i > 2 ? 1e3 : 1024, l && (m = -m), 0 === m ? (e[0] = 0, e[1] = p ? "" : "B") : ((-1 === h || isNaN(h)) && (h = Math.floor(Math.log(m) / Math.log(k))), h > 8 && (g = 1e3 * g * (h - 8), h = 8), g = 2 === i ? m / Math.pow(2, 10 * h) : m / Math.pow(1e3, h), j && (g = 8 * g, g > k && (g /= k, h++)), e[0] = Number(g.toFixed(h > 0 ? o : 0)), e[1] = c[j ? "bits" : "bytes"][h], !f && p && (j && b.test(e[1]) && (e[1] = e[1].toLowerCase()), e[1] = e[1].charAt(0), "B" === e[1] ? (e[0] = Math.floor(e[0]), e[1] = "") : j || "k" !== e[1] || (e[1] = "K"))), l && (e[0] = -e[0]), e[1] = r[e[1]] || e[1], "array" === n ? e : "exponent" === n ? h : "object" === n ? { value: e[0], suffix: e[1] } : e.join(q) }; "undefined" != typeof exports ? module.exports = d : "function" == typeof define ? define(function () { return d }) : a.filesize = d }("undefined" != typeof global ? global : window);
//# sourceMappingURL=filesize.min.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +0,0 @@
Handlebars.registerHelper('ifCond', function (v1, v2, options) {
if(v1 === v2) {
return options.fn(this);
}
return options.inverse(this);
});

View File

@@ -1,37 +0,0 @@
Handlebars.registerHelper('dateFormat', function (context, block) {
if (window.moment) {
var f = block.hash.format || "YYYY-MM-DD HH:mm:ss";
return moment(context).format(f); //had to remove Date(context)
} else {
return context; // moment plugin not available. return data as is.
}
});
Handlebars.registerHelper('jacketTimespan', function (context, block) {
var now = moment();
var from = moment(context);
var timeSpan = moment.duration(now.diff(from));
var minutes = timeSpan.asMinutes();
if (minutes < 120) {
return Math.round(minutes) + 'm ago';
}
var hours = timeSpan.asHours();
if (hours < 48) {
return Math.round(hours) + 'h ago';
}
var days = timeSpan.asDays();
if (days < 365) {
return Math.round(days) + 'd ago';
}
var years = timeSpan.asYears();
return Math.round(years) + 'y ago';
});
Handlebars.registerHelper('jacketSize', function (context, block) {
return filesize(context, { round: 1 });
});

View File

@@ -1,167 +0,0 @@
/*!
DataTables 1.10.13
©2008-2016 SpryMedia Ltd - datatables.net/license
*/
(function(h){"function"===typeof define&&define.amd?define(["jquery"],function(E){return h(E,window,document)}):"object"===typeof exports?module.exports=function(E,H){E||(E=window);H||(H="undefined"!==typeof window?require("jquery"):require("jquery")(E));return h(H,E,E.document)}:h(jQuery,window,document)})(function(h,E,H,k){function Y(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
d[c]=e,"o"===b[1]&&Y(a[e])});a._hungarianMap=d}function J(a,b,c){a._hungarianMap||Y(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),J(a[d],b[d],c)):b[d]=b[e]})}function Fa(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&F(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&F(a,a,"sZeroRecords","sLoadingRecords");
a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&fb(a)}function gb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX=
a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&J(m.models.oSearch,a[b])}function hb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function ib(a){if(!m.__browser){var b={};m.__browser=b;var c=h("<div/>").css({position:"fixed",top:0,left:-1*h(E).scrollLeft(),height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",
top:1,left:1,width:100,overflow:"scroll"}).append(h("<div/>").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,m.__browser);a.oScroll.iBarWidth=m.__browser.barWidth}function jb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!==
e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Ga(a,b){var c=m.defaults.column,d=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:H.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},m.models.oSearch,c[d]);la(a,d,h(b).data())}function la(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=
e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(hb(c),J(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),h.extend(b,c),F(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),F(b,c,"aDataSort"));var g=b.mData,j=R(g),i=b.mRender?R(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};
b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return S(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=
d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function Z(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ha(a);for(var c=0,d=b.length;c<d;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&ma(a);s(a,null,"column-sizing",[a])}function $(a,b){var c=na(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function aa(a,b){var c=na(a,"bVisible"),c=h.inArray(b,
c);return-1!==c?c:null}function ba(a){var b=0;h.each(a.aoColumns,function(a,d){d.bVisible&&"none"!==h(d.nTh).css("display")&&b++});return b}function na(a,b){var c=[];h.map(a.aoColumns,function(a,e){a[b]&&c.push(e)});return c}function Ia(a){var b=a.aoColumns,c=a.aoData,d=m.ext.type.detect,e,f,g,j,i,h,l,q,r;e=0;for(f=b.length;e<f;e++)if(l=b[e],r=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=d.length;g<j;g++){i=0;for(h=c.length;i<h;i++){r[i]===k&&(r[i]=B(a,i,e,"type"));
q=d[g](r[i],a);if(!q&&g!==d.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function kb(a,b,c,d){var e,f,g,j,i,n,l=a.aoColumns;if(b)for(e=b.length-1;0<=e;e--){n=b[e];var q=n.targets!==k?n.targets:n.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Ga(a);d(q[f],n)}else if("number"===typeof q[f]&&0>q[f])d(l.length+q[f],n);else if("string"===typeof q[f]){j=0;for(i=l.length;j<i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&
d(j,n)}}if(c){e=0;for(a=c.length;e<a;e++)d(e,c[e])}}function N(a,b,c,d){var e=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data",idx:e});f._aData=b;a.aoData.push(f);for(var g=a.aoColumns,j=0,i=g.length;j<i;j++)g[j].sType=null;a.aiDisplayMaster.push(e);b=a.rowIdFn(b);b!==k&&(a.aIds[b]=f);(c||!a.oFeatures.bDeferRender)&&Ja(a,e,c,d);return e}function oa(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,e){c=Ka(a,e);return N(a,c.data,e,c.cells)})}function B(a,b,c,d){var e=a.iDraw,
f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,i=f.fnGetData(g,d,{settings:a,row:b,col:c});if(i===k)return a.iDrawError!=e&&null===j&&(K(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b+", column "+c,4),a.iDrawError=e),j;if((i===g||null===i)&&null!==j&&d!==k)i=j;else if("function"===typeof i)return i.call(g);return null===i&&"display"==d?"":i}function lb(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,d,{settings:a,row:b,col:c})}
function La(a){return h.map(a.match(/(\\.|[^\.])+/g)||[""],function(a){return a.replace(/\\\./g,".")})}function R(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=R(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var g,j;if(""!==f){j=La(f);
for(var i=0,n=j.length;i<n;i++){f=j[i].match(ca);g=j[i].match(V);if(f){j[i]=j[i].replace(ca,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");if(h.isArray(a)){i=0;for(n=a.length;i<n;i++)g.push(c(a[i],b,j))}a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(V,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===k)return k;a=a[j[i]]}}return a};return function(b,e){return c(b,e,a)}}return function(b){return b[a]}}function S(a){if(h.isPlainObject(a))return S(a._);
if(null===a)return function(){};if("function"===typeof a)return function(b,d,e){a(b,"set",d,e)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,d,e){var e=La(e),f;f=e[e.length-1];for(var g,j,i=0,n=e.length-1;i<n;i++){g=e[i].match(ca);j=e[i].match(V);if(g){e[i]=e[i].replace(ca,"");a[e[i]]=[];f=e.slice();f.splice(0,i+1);g=f.join(".");if(h.isArray(d)){j=0;for(n=d.length;j<n;j++)f={},b(f,d[j],g),a[e[i]].push(f)}else a[e[i]]=d;return}j&&(e[i]=e[i].replace(V,
""),a=a[e[i]](d));if(null===a[e[i]]||a[e[i]]===k)a[e[i]]={};a=a[e[i]]}if(f.match(V))a[f.replace(V,"")](d);else a[f.replace(ca,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Ma(a){return D(a.aoData,"_aData")}function pa(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0;a.aIds={}}function qa(a,b,c){for(var d=-1,e=0,f=a.length;e<f;e++)a[e]==b?d=e:a[e]>b&&a[e]--; -1!=d&&c===k&&a.splice(d,1)}function da(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild);
c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ka(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}e._aSortData=null;e._aFilterData=null;g=a.aoColumns;if(d!==k)g[d].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;Na(a,e)}}function Ka(a,b,c,d){var e=[],f=b.firstChild,g,j,i=0,n,l=a.aoColumns,q=a._rowReadObject,d=d!==k?d:q?{}:[],r=function(a,b){if("string"===typeof a){var c=a.indexOf("@");
-1!==c&&(c=a.substring(c+1),S(a)(d,b.getAttribute(c)))}},m=function(a){if(c===k||c===i)j=l[i],n=h.trim(a.innerHTML),j&&j._bAttrSrc?(S(j.mData._)(d,n),r(j.mData.sort,a),r(j.mData.type,a),r(j.mData.filter,a)):q?(j._setter||(j._setter=S(j.mData)),j._setter(d,n)):d[i]=n;i++};if(f)for(;f;){g=f.nodeName.toUpperCase();if("TD"==g||"TH"==g)m(f),e.push(f);f=f.nextSibling}else{e=b.anCells;f=0;for(g=e.length;f<g;f++)m(e[f])}if(b=b.firstChild?b:b.nTr)(b=b.getAttribute("id"))&&S(a.rowId)(d,b);return{data:d,cells:e}}
function Ja(a,b,c,d){var e=a.aoData[b],f=e._aData,g=[],j,i,n,l,q;if(null===e.nTr){j=c||H.createElement("tr");e.nTr=j;e.anCells=g;j._DT_RowIndex=b;Na(a,e);l=0;for(q=a.aoColumns.length;l<q;l++){n=a.aoColumns[l];i=c?d[l]:H.createElement(n.sCellType);i._DT_CellIndex={row:b,column:l};g.push(i);if((!c||n.mRender||n.mData!==l)&&(!h.isPlainObject(n.mData)||n.mData._!==l+".display"))i.innerHTML=B(a,b,l,"display");n.sClass&&(i.className+=" "+n.sClass);n.bVisible&&!c?j.appendChild(i):!n.bVisible&&c&&i.parentNode.removeChild(i);
n.fnCreatedCell&&n.fnCreatedCell.call(a.oInstance,i,B(a,b,l),f,b,l)}s(a,"aoRowCreatedCallback",null,[j,f,b])}e.nTr.setAttribute("role","row")}function Na(a,b){var c=b.nTr,d=b._aData;if(c){var e=a.rowIdFn(d);e&&(c.id=e);d.DT_RowClass&&(e=d.DT_RowClass.split(" "),b.__rowc=b.__rowc?sa(b.__rowc.concat(e)):e,h(c).removeClass(b.__rowc.join(" ")).addClass(d.DT_RowClass));d.DT_RowAttr&&h(c).attr(d.DT_RowAttr);d.DT_RowData&&h(c).data(d.DT_RowData)}}function mb(a){var b,c,d,e,f,g=a.nTHead,j=a.nTFoot,i=0===
h("th, td",g).length,n=a.oClasses,l=a.aoColumns;i&&(e=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],d=h(f.nTh).addClass(f.sClass),i&&d.appendTo(e),a.oFeatures.bSort&&(d.addClass(f.sSortingClass),!1!==f.bSortable&&(d.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Oa(a,f.nTh,b))),f.sTitle!=d[0].innerHTML&&d.html(f.sTitle),Pa(a,"header")(a,d,f,n);i&&ea(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(n.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(n.sFooterTH);
if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function fa(a,b,c){var d,e,f,g=[],j=[],i=a.aoColumns.length,n;if(b){c===k&&(c=!1);d=0;for(e=b.length;d<e;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[d].splice(f,1);j.push([])}d=0;for(e=g.length;d<e;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(n=i=1,j[d][f]===k){a.appendChild(g[d][f].cell);
for(j[d][f]=1;g[d+i]!==k&&g[d][f].cell==g[d+i][f].cell;)j[d+i][f]=1,i++;for(;g[d][f+n]!==k&&g[d][f].cell==g[d][f+n].cell;){for(c=0;c<i;c++)j[d+c][f+n]=1;n++}h(g[d][f].cell).attr("rowspan",i).attr("colspan",n)}}}}function O(a){var b=s(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,d=a.asStripeClasses,e=d.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==y(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=
-1);var g=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!nb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:n;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ja(a,l);l=q.nTr;if(0!==e){var r=d[c%e];q._sRowStripe!=r&&(h(l).removeClass(q._sRowStripe).addClass(r),q._sRowStripe=r)}s(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,1==a.iDraw&&"ajax"==y(a)?c=f.sLoadingRecords:
f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":e?d[0]:""}).append(h("<td />",{valign:"top",colSpan:ba(a),"class":a.oClasses.sRowEmpty}).html(c))[0];s(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ma(a),g,n,i]);s(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ma(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));s(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function T(a,b){var c=a.oFeatures,d=c.bFilter;
c.bSort&&ob(a);d?ga(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;O(a);a._drawHold=!1}function pb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),d=a.oFeatures,e=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,k=0;k<f.length;k++){g=null;j=f[k];if("<"==j){i=h("<div/>")[0];
n=f[k+1];if("'"==n||'"'==n){l="";for(q=2;f[k+q]!=n;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=qb(a);else if("f"==j&&d.bFilter)g=rb(a);else if("r"==j&&d.bProcessing)g=sb(a);else if("t"==j)g=tb(a);else if("i"==j&&d.bInfo)g=ub(a);else if("p"==
j&&d.bPaginate)g=vb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q<n;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),e.append(g))}c.replaceWith(e);a.nHolding=null}function ea(a,b){var c=h(b).children("tr"),d,e,f,g,j,i,n,l,q,k;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){d=c[f];for(e=d.firstChild;e;){if("TD"==e.nodeName.toUpperCase()||"TH"==e.nodeName.toUpperCase()){l=1*e.getAttribute("colspan");
q=1*e.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;n=g;k=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][n+j]={cell:e,unique:k},a[f+g].nTr=d}e=e.nextSibling}}}function ta(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],ea(c,b)));for(var b=0,e=c.length;b<e;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function ua(a,b,c){s(a,"aoServerParams","serverParams",[b]);if(b&&h.isArray(b)){var d={},
e=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(e);c?(c=c[0],d[c]||(d[c]=[]),d[c].push(b.value)):d[b.name]=b.value});b=d}var f,g=a.ajax,j=a.oInstance,i=function(b){s(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var n=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&n?n:h.extend(!0,b,n);delete g.data}n={data:b,success:function(b){var c=b.error||b.sError;c&&K(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,c){var d=s(a,null,"xhr",
[a,null,a.jqXHR]);-1===h.inArray(!0,d)&&("parsererror"==c?K(a,0,"Invalid JSON response",1):4===b.readyState&&K(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;s(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(n,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(n,g)),g.data=f)}function nb(a){return a.bAjaxDataGet?(a.iDraw++,C(a,
!0),ua(a,wb(a),function(b){xb(a,b)}),!1):!0}function wb(a){var b=a.aoColumns,c=b.length,d=a.oFeatures,e=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,n,l,k=W(a);g=a._iDisplayStart;i=!1!==d.bPaginate?a._iDisplayLength:-1;var r=function(a,b){j.push({name:a,value:b})};r("sEcho",a.iDraw);r("iColumns",c);r("sColumns",D(b,"sName").join(","));r("iDisplayStart",g);r("iDisplayLength",i);var ra={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:e.sSearch,regex:e.bRegex}};for(g=0;g<c;g++)n=b[g],
l=f[g],i="function"==typeof n.mData?"function":n.mData,ra.columns.push({data:i,name:n.sName,searchable:n.bSearchable,orderable:n.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),r("mDataProp_"+g,i),d.bFilter&&(r("sSearch_"+g,l.sSearch),r("bRegex_"+g,l.bRegex),r("bSearchable_"+g,n.bSearchable)),d.bSort&&r("bSortable_"+g,n.bSortable);d.bFilter&&(r("sSearch",e.sSearch),r("bRegex",e.bRegex));d.bSort&&(h.each(k,function(a,b){ra.order.push({column:b.col,dir:b.dir});r("iSortCol_"+a,b.col);r("sSortDir_"+
a,b.dir)}),r("iSortingCols",k.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:ra:b?j:ra}function xb(a,b){var c=va(a,b),d=b.sEcho!==k?b.sEcho:b.draw,e=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(d){if(1*d<a.iDraw)return;a.iDraw=1*d}pa(a);a._iRecordsTotal=parseInt(e,10);a._iRecordsDisplay=parseInt(f,10);d=0;for(e=c.length;d<e;d++)N(a,c[d]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;O(a);a._bInitComplete||
wa(a,b);a.bAjaxDataGet=!0;C(a,!1)}function va(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?R(c)(b):b}function rb(a){var b=a.oClasses,c=a.sTableId,d=a.oLanguage,e=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),f=function(){var b=!this.value?
"":this.value;b!=e.sSearch&&(ga(a,{sSearch:b,bRegex:e.bRegex,bSmart:e.bSmart,bCaseInsensitive:e.bCaseInsensitive}),a._iDisplayStart=0,O(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===y(a)?400:0,i=h("input",b).val(e.sSearch).attr("placeholder",d.sSearchPlaceholder).on("keyup.DT search.DT input.DT paste.DT cut.DT",g?Qa(f,g):f).on("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==H.activeElement&&i.val(e.sSearch)}catch(d){}});
return b[0]}function ga(a,b,c){var d=a.oPreviousSearch,e=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};Ia(a);if("ssp"!=y(a)){yb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<e.length;b++)zb(a,e[b].sSearch,b,e[b].bEscapeRegex!==k?!e[b].bEscapeRegex:e[b].bRegex,e[b].bSmart,e[b].bCaseInsensitive);Ab(a)}else f(b);a.bFiltered=!0;s(a,null,"search",[a])}function Ab(a){for(var b=
m.ext.search,c=a.aiDisplay,d,e,f=0,g=b.length;f<g;f++){for(var j=[],i=0,n=c.length;i<n;i++)e=c[i],d=a.aoData[e],b[f](a,d._aFilterData,e,d._aData,i)&&j.push(e);c.length=0;h.merge(c,j)}}function zb(a,b,c,d,e,f){if(""!==b){for(var g=[],j=a.aiDisplay,d=Ra(b,d,e,f),e=0;e<j.length;e++)b=a.aoData[j[e]]._aFilterData[c],d.test(b)&&g.push(j[e]);a.aiDisplay=g}}function yb(a,b,c,d,e,f){var d=Ra(b,d,e,f),f=a.oPreviousSearch.sSearch,g=a.aiDisplayMaster,j,e=[];0!==m.ext.search.length&&(c=!0);j=Bb(a);if(0>=b.length)a.aiDisplay=
g.slice();else{if(j||c||f.length>b.length||0!==b.indexOf(f)||a.bSorted)a.aiDisplay=g.slice();b=a.aiDisplay;for(c=0;c<b.length;c++)d.test(a.aoData[b[c]]._sFilterRow)&&e.push(b[c]);a.aiDisplay=e}}function Ra(a,b,c,d){a=b?a:Sa(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,d?"i":"")}function Bb(a){var b=a.aoColumns,c,d,e,f,g,j,i,h,l=m.ext.type.search;c=!1;
d=0;for(f=a.aoData.length;d<f;d++)if(h=a.aoData[d],!h._aFilterData){j=[];e=0;for(g=b.length;e<g;e++)c=b[e],c.bSearchable?(i=B(a,d,e,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(xa.innerHTML=i,i=$b?xa.textContent:xa.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join(" ");c=!0}return c}function Cb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,
caseInsensitive:a.bCaseInsensitive}}function Db(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function ub(a){var b=a.sTableId,c=a.aanFeatures.i,d=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Eb,sName:"information"}),d.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return d[0]}function Eb(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,d=a._iDisplayStart+
1,e=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Fb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,d,e,f,g,j));h(b).html(j)}}function Fb(a,b){var c=a.fnFormatNumber,d=a._iDisplayStart+1,e=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===e;return b.replace(/_START_/g,c.call(a,d)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,
f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(d/e))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/e)))}function ha(a){var b,c,d=a.iInitDisplayStart,e=a.aoColumns,f;c=a.oFeatures;var g=a.bDeferLoading;if(a.bInitialised){pb(a);mb(a);fa(a,a.aoHeader);fa(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Ha(a);b=0;for(c=e.length;b<c;b++)f=e[b],f.sWidth&&(f.nTh.style.width=v(f.sWidth));s(a,null,"preInit",[a]);T(a);e=y(a);if("ssp"!=e||g)"ajax"==e?ua(a,[],function(c){var f=va(a,c);for(b=0;b<f.length;b++)N(a,f[b]);a.iInitDisplayStart=
d;T(a);C(a,!1);wa(a,c)},a):(C(a,!1),wa(a))}else setTimeout(function(){ha(a)},200)}function wa(a,b){a._bInitComplete=!0;(b||a.oInit.aaData)&&Z(a);s(a,null,"plugin-init",[a,b]);s(a,"aoInitComplete","init",[a,b])}function Ta(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Ua(a);s(a,null,"length",[a,c])}function qb(a){for(var b=a.oClasses,c=a.sTableId,d=a.aLengthMenu,e=h.isArray(d[0]),f=e?d[0]:d,d=e?d[1]:d,e=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)e[0][g]=
new Option(d[g],f[g]);var i=h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Ta(a,h(this).val());O(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function vb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){O(a)},b=h("<div/>").addClass(a.oClasses.sPaging+
b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;l<k;l++)Pa(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,e)},sName:"pagination"}));return b}function Va(a,b,c){var d=a._iDisplayStart,e=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===e?d=0:"number"===typeof b?(d=b*e,d>f&&
(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e<f&&(d+=e):"last"==b?d=Math.floor((f-1)/e)*e:K(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==d;a._iDisplayStart=d;b&&(s(a,null,"page",[a]),c&&O(a));return b}function sb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");
s(a,null,"processing",[a,b])}function tb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("<div/>",
{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left",
0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],r=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(r.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=r;a.aoDrawCallback.push({fn:ma,sName:"scrolling"});return i[0]}function ma(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"),
j=a.nScrollBody,l=h(j),q=j.style,r=h(a.nScrollFoot).children("div"),m=r.children("table"),p=h(a.nTHead),o=h(a.nTable),u=o[0],s=u.style,t=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,U=x.bScrollOversize,ac=D(a.aoColumns,"nTh"),P,L,Q,w,Wa=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};L=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==L&&a.scrollBarVis!==k)a.scrollBarVis=L,Z(a);else{a.scrollBarVis=L;o.children("thead, tfoot").remove();
t&&(Q=t.clone().prependTo(o),P=t.find("tr"),Q=Q.find("tr"));w=p.clone().prependTo(o);p=p.find("tr");L=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ta(a,w),function(b,c){B=$(a,b);c.style.width=a.aoColumns[B].sWidth});t&&I(function(a){a.style.width=""},Q);f=o.outerWidth();if(""===c){s.width="100%";if(U&&(o.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))s.width=v(o.outerWidth()-b);f=o.outerWidth()}else""!==d&&(s.width=
v(d),f=o.outerWidth());I(C,L);I(function(a){z.push(a.innerHTML);Wa.push(v(h(a).css("width")))},L);I(function(a,b){if(h.inArray(a,ac)!==-1)a.style.width=Wa[b]},p);h(L).height(0);t&&(I(C,Q),I(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},Q),I(function(a,b){a.style.width=y[b]},P),h(Q).height(0));I(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+z[b]+"</div>";a.style.width=Wa[b]},L);t&&I(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+
A[b]+"</div>";a.style.width=y[b]},Q);if(o.outerWidth()<f){P=j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(U&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))s.width=v(P-b);(""===c||""!==d)&&K(a,1,"Possible column misalignment",6)}else P="100%";q.width=v(P);g.width=v(P);t&&(a.nScrollFoot.style.width=v(P));!e&&U&&(q.height=v(u.offsetHeight+b));c=o.outerWidth();n[0].style.width=v(c);i.width=v(c);d=o.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+
(x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";t&&(m[0].style.width=v(c),r[0].style.width=v(c),r[0].style[e]=d?b+"px":"0px");o.children("colgroup").insertBefore(o.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function I(a,b,c){for(var d=0,e=0,f=b.length,g,j;e<f;){g=b[e].firstChild;for(j=c?c[e].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,d):a(g,d),d++),g=g.nextSibling,j=c?j.nextSibling:null;e++}}function Ha(a){var b=a.nTable,c=a.aoColumns,d=a.oScroll,
e=d.sY,f=d.sX,g=d.sXInner,j=c.length,i=na(a,"bVisible"),n=h("th",a.nTHead),l=b.getAttribute("width"),k=b.parentNode,r=!1,m,p,o=a.oBrowser,d=o.bScrollOversize;(m=b.style.width)&&-1!==m.indexOf("%")&&(l=m);for(m=0;m<i.length;m++)p=c[i[m]],null!==p.sWidth&&(p.sWidth=Gb(p.sWidthOrig,k),r=!0);if(d||!r&&!f&&!e&&j==ba(a)&&j==n.length)for(m=0;m<j;m++)i=$(a,m),null!==i&&(c[i].sWidth=v(n.eq(m).width()));else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var u=h("<tr/>").appendTo(j.find("tbody"));
j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=ta(a,j.find("thead")[0]);for(m=0;m<i.length;m++)p=c[i[m]],n[m].style.width=null!==p.sWidthOrig&&""!==p.sWidthOrig?v(p.sWidthOrig):"",p.sWidthOrig&&f&&h(n[m]).append(h("<div/>").css({width:p.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m<i.length;m++)r=i[m],p=c[r],h(Hb(a,r)).clone(!1).append(p.sContentPadding).appendTo(u);h("[name]",
j).removeAttr("name");p=h("<div/>").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()<k.clientWidth&&l&&j.width(k.clientWidth)):e?j.width(k.clientWidth):l&&j.width(l);for(m=e=0;m<i.length;m++)k=h(n[m]),g=k.outerWidth()-k.width(),k=o.bBounding?Math.ceil(n[m].getBoundingClientRect().width):k.outerWidth(),e+=k,c[i[m]].sWidth=v(k-g);b.style.width=v(e);p.remove()}l&&(b.style.width=
v(l));if((l||f)&&!a._reszEvt)b=function(){h(E).on("resize.DT-"+a.sInstance,Qa(function(){Z(a)}))},d?setTimeout(b,1E3):b(),a._reszEvt=!0}function Gb(a,b){if(!a)return 0;var c=h("<div/>").css("width",v(a)).appendTo(b||H.body),d=c[0].offsetWidth;c.remove();return d}function Hb(a,b){var c=Ib(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("<td/>").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Ib(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;f<g;f++)c=B(a,f,b,"display")+"",c=c.replace(bc,
""),c=c.replace(/&nbsp;/g," "),c.length>d&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function W(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<n.length;a++){i=n[a][0];f=e[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=e[g].sType||
"string",n[a]._idx===k&&(n[a]._idx=h.inArray(n[a][1],e[g].asSorting)),d.push({src:i,col:g,dir:n[a][1],index:n[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return d}function ob(a){var b,c,d=[],e=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;Ia(a);h=W(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Jb(a,j.col);if("ssp"!=y(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)d[i[b]]=b;g===h.length?i.sort(function(a,b){var c,e,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=
0;g<i;g++)if(j=h[g],c=k[j.col],e=m[j.col],c=c<e?-1:c>e?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return c<e?-1:c>e?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,p=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=p[i.col],i=e[i.type+"-"+i.dir]||e["string-"+i.dir],c=i(c,g),0!==c)return c;c=d[a];g=d[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Kb(a){for(var b,c,d=a.aoColumns,e=W(a),a=a.oLanguage.oAria,f=0,g=d.length;f<g;f++){c=d[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,
"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<e.length&&e[0].col==f?(i.setAttribute("aria-sort","asc"==e[0].dir?"ascending":"descending"),c=j[e[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",b)}}function Xa(a,b,c,d){var e=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof e[0]&&(e=a.aaSorting=[e]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,
D(e,"0")),-1!==c?(b=g(e[c],!0),null===b&&1===e.length&&(b=0),null===b?e.splice(c,1):(e[c][1]=f[b],e[c]._idx=b)):(e.push([b,f[0],0]),e[e.length-1]._idx=0)):e.length&&e[0][0]==b?(b=g(e[0]),e.length=1,e[0][1]=f[b],e[0]._idx=b):(e.length=0,e.push([b,f[0]]),e[0]._idx=0);T(a);"function"==typeof d&&d(a)}function Oa(a,b,c,d){var e=a.aoColumns[c];Ya(b,{},function(b){!1!==e.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Xa(a,c,b.shiftKey,d);"ssp"!==y(a)&&C(a,!1)},0)):Xa(a,c,b.shiftKey,d))})}
function ya(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,d=W(a),e=a.oFeatures,f,g;if(e.bSort&&e.bSortClasses){e=0;for(f=b.length;e<f;e++)g=b[e].src,h(D(a.aoData,"anCells",g)).removeClass(c+(2>e?e+1:3));e=0;for(f=d.length;e<f;e++)g=d[e].src,h(D(a.aoData,"anCells",g)).addClass(c+(2>e?e+1:3))}a.aLastSort=d}function Jb(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,aa(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],
c._aSortData||(c._aSortData=[]),!c._aSortData[b]||d)f=d?e[j]:B(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function za(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),search:Cb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,d){return{visible:b.bVisible,search:Cb(a.aoPreSearchCols[d])}})};s(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,
b)}}function Lb(a,b,c){var d,e,f=a.aoColumns,b=function(b){if(b&&b.time){var i=s(a,"aoStateLoadParams","stateLoadParams",[a,g]);if(-1===h.inArray(!1,i)&&(i=a.iStateDuration,!(0<i&&b.time<+new Date-1E3*i)&&!(b.columns&&f.length!==b.columns.length))){a.oLoadedState=h.extend(!0,{},g);b.start!==k&&(a._iDisplayStart=b.start,a.iInitDisplayStart=b.start);b.length!==k&&(a._iDisplayLength=b.length);b.order!==k&&(a.aaSorting=[],h.each(b.order,function(b,c){a.aaSorting.push(c[0]>=f.length?[0,c[1]]:c)}));b.search!==
k&&h.extend(a.oPreviousSearch,Db(b.search));if(b.columns){d=0;for(e=b.columns.length;d<e;d++)i=b.columns[d],i.visible!==k&&(f[d].bVisible=i.visible),i.search!==k&&h.extend(a.aoPreSearchCols[d],Db(i.search))}s(a,"aoStateLoaded","stateLoaded",[a,g])}}c()};if(a.oFeatures.bStateSave){var g=a.fnStateLoadCallback.call(a.oInstance,a,b);g!==k&&b(g)}else c()}function Aa(a){var b=m.settings,a=h.inArray(a,D(b,"nTable"));return-1!==a?b[a]:null}function K(a,b,c,d){c="DataTables warning: "+(a?"table id="+a.sTableId+
" - ":"")+c;d&&(c+=". For more information about this error, please see http://datatables.net/tn/"+d);if(b)E.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,a&&s(a,null,"error",[a,d,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,d,c)}}function F(a,b,c,d){h.isArray(c)?h.each(c,function(c,d){h.isArray(d)?F(a,b,d[0],d[1]):F(a,b,d)}):(d===k&&(d=c),b[c]!==k&&(a[d]=b[c]))}function Mb(a,b,c){var d,e;for(e in b)b.hasOwnProperty(e)&&(d=b[e],
h.isPlainObject(d)?(h.isPlainObject(a[e])||(a[e]={}),h.extend(!0,a[e],d)):a[e]=c&&"data"!==e&&"aaData"!==e&&h.isArray(d)?d.slice():d);return a}function Ya(a,b,c){h(a).on("click.DT",b,function(b){a.blur();c(b)}).on("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).on("selectstart.DT",function(){return!1})}function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function s(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&(b=h.Event(c+
".dt"),h(a.nTable).trigger(b,d),e.push(b.result));return e}function Ua(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),d=a._iDisplayLength;b>=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Pa(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ia(a,b){var c=[],c=Nb.numbers_length,d=Math.floor(c/2);b<=c?c=X(0,b):a<=d?(c=X(0,
c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=X(b-(c-2),b):(c=X(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function fb(a){h.each({num:function(b){return Ba(b,a)},"num-fmt":function(b){return Ba(b,a,Za)},"html-num":function(b){return Ba(b,a,Ca)},"html-num-fmt":function(b){return Ba(b,a,Ca,Za)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Ob(a){return function(){var b=
[Aa(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new u(Aa(this[x.iApiIndex])):new u(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=
function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&ma(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};
this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();
return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return Aa(this[x.iApiIndex])};
this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in m.ext.internal)e&&(this[e]=Ob(e));this.each(function(){var e={},g=1<d?Mb(e,a,!0):
a,j=0,i,e=this.getAttribute("id"),n=!1,l=m.defaults,q=h(this);if("table"!=this.nodeName.toLowerCase())K(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{gb(l);hb(l.column);J(l,l,!0);J(l.column,l.column,!0);J(l,h.extend(g,q.data()));var r=m.settings,j=0;for(i=r.length;j<i;j++){var p=r[j];if(p.nTable==this||p.nTHead.parentNode==this||p.nTFoot&&p.nTFoot.parentNode==this){var u=g.bRetrieve!==k?g.bRetrieve:l.bRetrieve;if(c||u)return p.oInstance;if(g.bDestroy!==k?g.bDestroy:l.bDestroy){p.oInstance.fnDestroy();
break}else{K(p,0,"Cannot reinitialise DataTable",3);return}}if(p.sTableId==this.id){r.splice(j,1);break}}if(null===e||""===e)this.id=e="DataTables_Table_"+m.ext._unique++;var o=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:e,sTableId:e});o.nTable=this;o.oApi=b.internal;o.oInit=g;r.push(o);o.oInstance=1===b.length?b:q.dataTable();gb(g);g.oLanguage&&Fa(g.oLanguage);g.aLengthMenu&&!g.iDisplayLength&&(g.iDisplayLength=h.isArray(g.aLengthMenu[0])?g.aLengthMenu[0][0]:g.aLengthMenu[0]);
g=Mb(h.extend(!0,{},l),g);F(o.oFeatures,g,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));F(o,g,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback","renderer","searchDelay","rowId",["iCookieDuration","iStateDuration"],
["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);F(o.oScroll,g,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);F(o.oLanguage,g,"fnInfoCallback");z(o,"aoDrawCallback",g.fnDrawCallback,"user");z(o,"aoServerParams",g.fnServerParams,"user");z(o,"aoStateSaveParams",g.fnStateSaveParams,"user");z(o,"aoStateLoadParams",g.fnStateLoadParams,"user");z(o,"aoStateLoaded",g.fnStateLoaded,
"user");z(o,"aoRowCallback",g.fnRowCallback,"user");z(o,"aoRowCreatedCallback",g.fnCreatedRow,"user");z(o,"aoHeaderCallback",g.fnHeaderCallback,"user");z(o,"aoFooterCallback",g.fnFooterCallback,"user");z(o,"aoInitComplete",g.fnInitComplete,"user");z(o,"aoPreDrawCallback",g.fnPreDrawCallback,"user");o.rowIdFn=R(g.rowId);ib(o);var t=o.oClasses;g.bJQueryUI?(h.extend(t,m.ext.oJUIClasses,g.oClasses),g.sDom===l.sDom&&"lfrtip"===l.sDom&&(o.sDom='<"H"lfr>t<"F"ip>'),o.renderer)?h.isPlainObject(o.renderer)&&
!o.renderer.header&&(o.renderer.header="jqueryui"):o.renderer="jqueryui":h.extend(t,m.ext.classes,g.oClasses);q.addClass(t.sTable);o.iInitDisplayStart===k&&(o.iInitDisplayStart=g.iDisplayStart,o._iDisplayStart=g.iDisplayStart);null!==g.iDeferLoading&&(o.bDeferLoading=!0,e=h.isArray(g.iDeferLoading),o._iRecordsDisplay=e?g.iDeferLoading[0]:g.iDeferLoading,o._iRecordsTotal=e?g.iDeferLoading[1]:g.iDeferLoading);var v=o.oLanguage;h.extend(!0,v,g.oLanguage);v.sUrl&&(h.ajax({dataType:"json",url:v.sUrl,success:function(a){Fa(a);
J(l.oLanguage,a);h.extend(true,v,a);ha(o)},error:function(){ha(o)}}),n=!0);null===g.asStripeClasses&&(o.asStripeClasses=[t.sStripeOdd,t.sStripeEven]);var e=o.asStripeClasses,x=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(e,function(a){return x.hasClass(a)}))&&(h("tbody tr",this).removeClass(e.join(" ")),o.asDestroyStripes=e.slice());e=[];r=this.getElementsByTagName("thead");0!==r.length&&(ea(o.aoHeader,r[0]),e=ta(o));if(null===g.aoColumns){r=[];j=0;for(i=e.length;j<i;j++)r.push(null)}else r=
g.aoColumns;j=0;for(i=r.length;j<i;j++)Ga(o,e?e[j]:null);kb(o,g.aoColumnDefs,r,function(a,b){la(o,a,b)});if(x.length){var w=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h(x[0]).children("th, td").each(function(a,b){var c=o.aoColumns[a];if(c.mData===a){var d=w(b,"sort")||w(b,"order"),e=w(b,"filter")||w(b,"search");if(d!==null||e!==null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};la(o,a)}}})}var U=o.oFeatures,
e=function(){if(g.aaSorting===k){var a=o.aaSorting;j=0;for(i=a.length;j<i;j++)a[j][1]=o.aoColumns[j].asSorting[0]}ya(o);U.bSort&&z(o,"aoDrawCallback",function(){if(o.bSorted){var a=W(o),b={};h.each(a,function(a,c){b[c.src]=c.dir});s(o,null,"order",[o,a,b]);Kb(o)}});z(o,"aoDrawCallback",function(){(o.bSorted||y(o)==="ssp"||U.bDeferRender)&&ya(o)},"sc");var a=q.children("caption").each(function(){this._captionSide=h(this).css("caption-side")}),b=q.children("thead");b.length===0&&(b=h("<thead/>").appendTo(q));
o.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("<tbody/>").appendTo(q));o.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(o.oScroll.sX!==""||o.oScroll.sY!==""))b=h("<tfoot/>").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(t.sNoFooter);else if(b.length>0){o.nTFoot=b[0];ea(o.aoFooter,o.nTFoot)}if(g.aaData)for(j=0;j<g.aaData.length;j++)N(o,g.aaData[j]);else(o.bDeferLoading||y(o)=="dom")&&oa(o,h(o.nTBody).children("tr"));o.aiDisplay=o.aiDisplayMaster.slice();
o.bInitialised=true;n===false&&ha(o)};g.bStateSave?(U.bStateSave=!0,z(o,"aoDrawCallback",za,"state_save"),Lb(o,g,e)):e()}});b=null;return this},x,u,p,t,$a={},Pb=/[\r\n]/g,Ca=/<.*?>/g,cc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,dc=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Za=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,M=function(a){return!a||!0===a||"-"===a?!0:!1},Qb=function(a){var b=parseInt(a,10);return!isNaN(b)&&
isFinite(a)?b:null},Rb=function(a,b){$a[b]||($a[b]=RegExp(Sa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace($a[b],"."):a},ab=function(a,b,c){var d="string"===typeof a;if(M(a))return!0;b&&d&&(a=Rb(a,b));c&&d&&(a=a.replace(Za,""));return!isNaN(parseFloat(a))&&isFinite(a)},Sb=function(a,b,c){return M(a)?!0:!(M(a)||"string"===typeof a)?null:ab(a.replace(Ca,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;e<f;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;e<
f;e++)a[e]&&d.push(a[e][b]);return d},ja=function(a,b,c,d){var e=[],f=0,g=b.length;if(d!==k)for(;f<g;f++)a[b[f]][c]&&e.push(a[b[f]][c][d]);else for(;f<g;f++)e.push(a[b[f]][c]);return e},X=function(a,b){var c=[],d;b===k?(b=0,d=a):(d=b,b=a);for(var e=b;e<d;e++)c.push(e);return c},Tb=function(a){for(var b=[],c=0,d=a.length;c<d;c++)a[c]&&b.push(a[c]);return b},sa=function(a){var b=[],c,d,e=a.length,f,g=0;d=0;a:for(;d<e;d++){c=a[d];for(f=0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b};m.util=
{throttle:function(a,b){var c=b!==k?b:200,d,e;return function(){var b=this,g=+new Date,h=arguments;d&&g<d+c?(clearTimeout(e),e=setTimeout(function(){d=k;a.apply(b,h)},c)):(d=g,a.apply(b,h))}},escapeRegex:function(a){return a.replace(dc,"\\$1")}};var A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ca=/\[.*?\]$/,V=/\(\)$/,Sa=m.util.escapeRegex,xa=h("<div>")[0],$b=xa.textContent!==k,bc=/<.*?>/g,Qa=m.util.throttle,Ub=[],w=Array.prototype,ec=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});
if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};u=function(a,b){if(!(this instanceof u))return new u(a,b);var c=[],d=function(a){(a=ec(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;e<f;e++)d(a[e]);
else d(a);this.context=sa(c);b&&h.merge(this,b);this.selector={rows:null,cols:null,opts:null};u.extend(this,this,Ub)};m.Api=u;h.extend(u.prototype,{any:function(){return 0!==this.count()},concat:w.concat,context:[],count:function(){return this.flatten().length},each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new u(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);
else for(var c=0,d=this.length;c<d;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new u(this.context,b)},flatten:function(){var a=[];return new u(this.context,a.concat.apply(a,this.toArray()))},join:w.join,indexOf:w.indexOf||function(a,b){for(var c=b||0,d=this.length;c<d;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,d){var e=[],f,g,h,i,n,l=this.context,m,p,t=this.selector;"string"===typeof a&&(d=c,c=b,b=a,a=!1);g=0;for(h=l.length;g<h;g++){var s=new u(l[g]);if("table"===b)f=
c.call(s,l[g],g),f!==k&&e.push(f);else if("columns"===b||"rows"===b)f=c.call(s,l[g],this[g],g),f!==k&&e.push(f);else if("column"===b||"column-rows"===b||"row"===b||"cell"===b){p=this[g];"column-rows"===b&&(m=Da(l[g],t.opts));i=0;for(n=p.length;i<n;i++)f=p[i],f="cell"===b?c.call(s,l[g],f.row,f.column,g,i):c.call(s,l[g],f,g,i,m),f!==k&&e.push(f)}}return e.length||d?(a=new u(l,a?e.concat.apply([],e):e),b=a.selector,b.rows=t.rows,b.cols=t.cols,b.opts=t.opts,a):this},lastIndexOf:w.lastIndexOf||function(a,
b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(w.map)b=w.map.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)b.push(a.call(this,this[c],c));return new u(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:w.pop,push:w.push,reduce:w.reduce||function(a,b){return jb(this,a,b,0,this.length,1)},reduceRight:w.reduceRight||function(a,b){return jb(this,a,b,this.length-1,-1,-1)},reverse:w.reverse,selector:null,shift:w.shift,
sort:w.sort,splice:w.splice,toArray:function(){return w.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},unique:function(){return new u(this.context,sa(this))},unshift:w.unshift});u.extend=function(a,b,c){if(c.length&&b&&(b instanceof u||b.__dt_wrapper)){var d,e,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);u.extend(d,d,c.methodExt);return d}};d=0;for(e=c.length;d<e;d++)f=c[d],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?
{}:f.val,b[f.name].__dt_wrapper=!0,u.extend(a,b[f.name],f.propExt)}};u.register=p=function(a,b){if(h.isArray(a))for(var c=0,d=a.length;c<d;c++)u.register(a[c],b);else for(var e=a.split("."),f=Ub,g,j,c=0,d=e.length;c<d;c++){g=(j=-1!==e[c].indexOf("()"))?e[c].replace("()",""):e[c];var i;a:{i=0;for(var n=f.length;i<n;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===d-1?i.val=b:f=j?i.methodExt:i.propExt}};u.registerPlural=t=function(a,b,c){u.register(a,
c);u.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof u?a.length?h.isArray(a[0])?new u(a.context,a[0]):a[0]:k:a})};p("tables()",function(a){var b;if(a){b=u;var c=this.context;if("number"===typeof a)a=[c[a]];else var d=h.map(c,function(a){return a.nTable}),a=h(d).filter(a).map(function(){var a=h.inArray(this,d);return c[a]}).toArray();b=new b(a)}else b=this;return b});p("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new u(b[0]):a});t("tables().nodes()",
"table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});t("tables().body()","table().body()",function(){return this.iterator("table",function(a){return a.nTBody},1)});t("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});t("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});t("tables().containers()","table().container()",function(){return this.iterator("table",
function(a){return a.nTableWrapper},1)});p("draw()",function(a){return this.iterator("table",function(b){"page"===a?O(b):("string"===typeof a&&(a="full-hold"===a?!1:!0),T(b,!1===a))})});p("page()",function(a){return a===k?this.page.info().page:this.iterator("table",function(b){Va(b,a)})});p("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a.oFeatures.bPaginate?a._iDisplayLength:-1,d=a.fnRecordsDisplay(),e=-1===c;return{page:e?0:Math.floor(b/c),
pages:e?1:Math.ceil(d/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:d,serverSide:"ssp"===y(a)}});p("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:k:this.iterator("table",function(b){Ta(b,a)})});var Vb=function(a,b,c){if(c){var d=new u(a);d.one("draw",function(){c(d.ajax.json())})}if("ssp"==y(a))T(a,b);else{C(a,!0);var e=a.jqXHR;e&&4!==e.readyState&&e.abort();ua(a,[],function(c){pa(a);for(var c=va(a,c),d=0,e=c.length;d<
e;d++)N(a,c[d]);T(a,b);C(a,!1)})}};p("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});p("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});p("ajax.reload()",function(a,b){return this.iterator("table",function(c){Vb(c,!1===b,a)})});p("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?
b.ajax.url=a:b.ajax=a})});p("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Vb(c,!1===b,a)})});var bb=function(a,b,c,d,e){var f=[],g,j,i,n,l,m;i=typeof b;if(!b||"string"===i||"function"===i||b.length===k)b=[b];i=0;for(n=b.length;i<n;i++){j=b[i]&&b[i].split&&!b[i].match(/[\[\(:]/)?b[i].split(","):[b[i]];l=0;for(m=j.length;l<m;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&(f=f.concat(g))}a=x.selector[a];if(a.length){i=0;for(n=a.length;i<n;i++)f=a[i](d,e,f)}return sa(f)},
cb=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",page:"all"},a)},db=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},Da=function(a,b){var c,d,e,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;d=b.order;e=b.page;if("ssp"==y(a))return"removed"===j?[]:X(0,c.length);if("current"==e){c=a._iDisplayStart;for(d=a.fnDisplayEnd();c<d;c++)f.push(g[c])}else if("current"==
d||"applied"==d)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==d||"original"==d){c=0;for(d=a.aoData.length;c<d;c++)"none"==j?f.push(c):(e=h.inArray(c,g),(-1===e&&"removed"==j||0<=e&&"applied"==j)&&f.push(c))}return f};p("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=cb(b),c=this.iterator("table",function(c){var e=b,f;return bb("row",a,function(a){var b=Qb(a);if(b!==null&&!e)return[b];f||(f=Da(c,e));if(b!==
null&&h.inArray(b,f)!==-1)return[b];if(a===null||a===k||a==="")return f;if(typeof a==="function")return h.map(f,function(b){var e=c.aoData[b];return a(b,e._aData,e.nTr)?b:null});b=Tb(ja(c.aoData,f,"nTr"));if(a.nodeName){if(a._DT_RowIndex!==k)return[a._DT_RowIndex];if(a._DT_CellIndex)return[a._DT_CellIndex.row];b=h(a).closest("*[data-dt-row]");return b.length?[b.data("dt-row")]:[]}if(typeof a==="string"&&a.charAt(0)==="#"){var i=c.aIds[a.replace(/^#/,"")];if(i!==k)return[i.idx]}return h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},
c,e)},1);c.selector.rows=a;c.selector.opts=b;return c});p("rows().nodes()",function(){return this.iterator("row",function(a,b){return a.aoData[b].nTr||k},1)});p("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ja(a.aoData,b,"_aData")},1)});t("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var d=b.aoData[c];return"search"===a?d._aFilterData:d._aSortData},1)});t("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",
function(b,c){da(b,c,a)})});t("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,b){return b},1)});t("rows().ids()","row().id()",function(a){for(var b=[],c=this.context,d=0,e=c.length;d<e;d++)for(var f=0,g=this[d].length;f<g;f++){var h=c[d].rowIdFn(c[d].aoData[this[d][f]]._aData);b.push((!0===a?"#":"")+h)}return new u(c,b)});t("rows().remove()","row().remove()",function(){var a=this;this.iterator("row",function(b,c,d){var e=b.aoData,f=e[c],g,h,i,n,l;e.splice(c,1);
g=0;for(h=e.length;g<h;g++)if(i=e[g],l=i.anCells,null!==i.nTr&&(i.nTr._DT_RowIndex=g),null!==l){i=0;for(n=l.length;i<n;i++)l[i]._DT_CellIndex.row=g}qa(b.aiDisplayMaster,c);qa(b.aiDisplay,c);qa(a[d],c,!1);Ua(b);c=b.rowIdFn(f._aData);c!==k&&delete b.aIds[c]});this.iterator("table",function(a){for(var c=0,d=a.aoData.length;c<d;c++)a.aoData[c].idx=c});return this});p("rows.add()",function(a){var b=this.iterator("table",function(b){var c,f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?
h.push(oa(b,c)[0]):h.push(N(b,c));return h},1),c=this.rows(-1);c.pop();h.merge(c,b);return c});p("row()",function(a,b){return db(this.rows(a,b))});p("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;da(b[0],this[0],"data");return this});p("row().node()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]].nTr||null:null});p("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);
var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?oa(b,a)[0]:N(b,a)});return this.row(b[0])});var eb=function(a,b){var c=a.context;if(c.length&&(c=c[0].aoData[b!==k?b:a[0]])&&c._details)c._details.remove(),c._detailsShow=k,c._details=k},Wb=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];if(d._details){(d._detailsShow=b)?d._details.insertAfter(d.nTr):d._details.detach();var e=c[0],f=new u(e),g=e.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");
0<D(g,"_details").length&&(f.on("draw.dt.DT_details",function(a,b){e===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(e===b)for(var c,d=ba(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",d)}),f.on("destroy.dt.DT_details",function(a,b){if(e===b)for(var c=0,d=g.length;c<d;c++)g[c]._details&&eb(f,c)}))}}};p("row().child()",function(a,b){var c=
this.context;if(a===k)return c.length&&this.length?c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)eb(this);else if(c.length&&this.length){var d=c[0],c=c[0].aoData[this[0]],e=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?e.push(a):(c=h("<tr><td/></tr>").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=ba(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);
c._detailsShow&&c._details.insertAfter(c.nTr)}return this});p(["row().child.show()","row().child().show()"],function(){Wb(this,!0);return this});p(["row().child.hide()","row().child().hide()"],function(){Wb(this,!1);return this});p(["row().child.remove()","row().child().remove()"],function(){eb(this);return this});p("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var fc=/^([^:]+):(name|visIdx|visible)$/,Xb=function(a,b,
c,d,e){for(var c=[],d=0,f=e.length;d<f;d++)c.push(B(a,e[d],b));return c};p("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=cb(b),c=this.iterator("table",function(c){var e=a,f=b,g=c.aoColumns,j=D(g,"sName"),i=D(g,"nTh");return bb("column",e,function(a){var b=Qb(a);if(a==="")return X(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var e=Da(c,f);return h.map(g,function(b,f){return a(f,Xb(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(fc):
"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[$(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},
1);c.selector.cols=a;c.selector.opts=b;return c});t("columns().header()","column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});t("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});t("columns().data()","column().data()",function(){return this.iterator("column-rows",Xb,1)});t("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},
1)});t("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ja(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});t("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ja(a.aoData,e,"anCells",b)},1)});t("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,
i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m=h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(n=j.length;i<n;i++)l=j[i].nTr,f=j[i].anCells,l&&l.insertBefore(f[c],f[m]||null)}else h(D(b.aoData,"anCells",c)).detach();g.bVisible=a;fa(b,b.aoHeader);fa(b,b.aoFooter);za(b)}});a!==k&&(this.iterator("column",function(c,e){s(c,null,"column-visibility",[c,e,a,b])}),(b===k||b)&&this.columns.adjust());return c});t("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===
a?aa(b,c):c},1)});p("columns.adjust()",function(){return this.iterator("table",function(a){Z(a)},1)});p("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return $(c,b);if("fromData"===a||"toVisible"===a)return aa(c,b)}});p("column()",function(a,b){return db(this.columns(a,b))});p("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",
function(b){var d=a,e=cb(c),f=b.aoData,g=Da(b,e),i=Tb(ja(f,g,"anCells")),j=h([].concat.apply([],i)),l,n=b.aoColumns.length,m,p,t,u,s,v;return bb("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){m=[];p=0;for(t=g.length;p<t;p++){l=g[p];for(u=0;u<n;u++){s={row:l,column:u};if(c){v=f[l];a(s,B(b,l,u),v.anCells?v.anCells[u]:null)&&m.push(s)}else m.push(s)}}return m}if(h.isPlainObject(a))return[a];c=j.filter(a).map(function(a,b){return{row:b._DT_CellIndex.row,column:b._DT_CellIndex.column}}).toArray();
if(c.length||!a.nodeName)return c;v=h(a).closest("*[data-dt-row]");return v.length?[{row:v.data("dt-row"),column:v.data("dt-column")}]:[]},b,e)});var d=this.columns(b,c),e=this.rows(a,c),f,g,j,i,n,l=this.iterator("table",function(a,b){f=[];g=0;for(j=e[b].length;g<j;g++){i=0;for(n=d[b].length;i<n;i++)f.push({row:e[b][g],column:d[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});t("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=
a.aoData[b])&&a.anCells?a.anCells[c]:k},1)});p("cells().data()",function(){return this.iterator("cell",function(a,b,c){return B(a,b,c)},1)});t("cells().cache()","cell().cache()",function(a){a="search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,d){return b.aoData[c][a][d]},1)});t("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,d){return B(b,c,d,a)},1)});t("cells().indexes()","cell().index()",function(){return this.iterator("cell",
function(a,b,c){return{row:b,column:c,columnVisible:aa(a,c)}},1)});t("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,d){da(b,c,a,d)})});p("cell()",function(a,b,c){return db(this.cells(a,b,c))});p("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?B(b[0],c[0].row,c[0].column):k;lb(b[0],c[0].row,c[0].column,a);da(b[0],c[0].row,"data",c[0].column);return this});p("order()",function(a,b){var c=this.context;if(a===
k)return 0!==c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:a.length&&!h.isArray(a[0])&&(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});p("order.listener()",function(a,b,c){return this.iterator("table",function(d){Oa(d,a,b,c)})});p("order.fixed()",function(a){if(!a){var b=this.context,b=b.length?b[0].aaSortingFixed:k;return h.isArray(b)?{pre:b}:b}return this.iterator("table",function(b){b.aaSortingFixed=h.extend(!0,{},a)})});p(["columns().order()",
"column().order()"],function(a){var b=this;return this.iterator("table",function(c,d){var e=[];h.each(b[d],function(b,c){e.push([c,a])});c.aaSorting=e})});p("search()",function(a,b,c,d){var e=this.context;return a===k?0!==e.length?e[0].oPreviousSearch.sSearch:k:this.iterator("table",function(e){e.oFeatures.bFilter&&ga(e,h.extend({},e.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),1)})});t("columns().search()","column().search()",function(a,
b,c,d){return this.iterator("column",function(e,f){var g=e.aoPreSearchCols;if(a===k)return g[f].sSearch;e.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),ga(e,e.oPreviousSearch,1))})});p("state()",function(){return this.context.length?this.context[0].oSavedState:null});p("state.clear()",function(){return this.iterator("table",function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});p("state.loaded()",function(){return this.context.length?
this.context[0].oLoadedState:null});p("state.save()",function(){return this.iterator("table",function(a){za(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,d,e=0,f=a.length;e<f;e++)if(c=parseInt(b[e],10)||0,d=parseInt(a[e],10)||0,c!==d)return c>d;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof m.Api)return!0;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?
h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new u(c):c};m.camelToHungarian=J;p("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){p(b+"()",function(){var a=Array.prototype.slice.call(arguments);
a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});p("clear()",function(){return this.iterator("table",function(a){pa(a)})});p("settings()",function(){return new u(this.context,this.context)});p("init()",function(){var a=this.context;return a.length?a[0].oInit:null});p("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});p("destroy()",function(a){a=a||
!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),p;b.bDestroying=!0;s(b,"aoDestroyCallback","destroy",[b]);a||(new u(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));
b.aaSorting=[];b.aaSortingFixed=[];ya(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);b.bJUI&&(h("th span."+d.sSortIcon+", td span."+d.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+d.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",
b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%p])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column","row","cell"],function(a,b){p(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,m){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,m)})})});p("i18n()",function(a,b,c){var d=this.context[0],a=R(a)(d.oLanguage);a===k&&(a=b);c!==
k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.13";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,
mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,
bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?
sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",
sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},
oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};Y(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,
sType:null,sWidth:null};Y(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],
aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,
searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],
fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,
aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=x={buttons:{},classes:{},builder:"-source-",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,
oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",
sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",
sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Ea="",Ea="",G=Ea+"ui-state-default",ka=Ea+"css_right ui-icon ui-icon-",Yb=Ea+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses,m.ext.classes,{sPageButton:"fg-button ui-button "+G,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:G+" sorting_asc",
sSortDesc:G+" sorting_desc",sSortable:G+" sorting",sSortableAsc:G+" sorting_asc_disabled",sSortableDesc:G+" sorting_desc_disabled",sSortableNone:G+" sorting_disabled",sSortJUIAsc:ka+"triangle-1-n",sSortJUIDesc:ka+"triangle-1-s",sSortJUI:ka+"carat-2-n-s",sSortJUIAscAllowed:ka+"carat-1-n",sSortJUIDescAllowed:ka+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+G,sScrollFoot:"dataTables_scrollFoot "+G,sHeaderTH:G,sFooterTH:G,sJUIHeader:Yb+
" ui-corner-tl ui-corner-tr",sJUIFooter:Yb+" ui-corner-bl ui-corner-br"});var Nb=m.ext.pager;h.extend(Nb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ia(a,b)]},simple_numbers:function(a,b){return["previous",ia(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ia(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ia(a,b),"last"]},_numbers:ia,numbers_length:7});h.extend(!0,m.ext.renderer,
{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},m,l,p=0,r=function(b,d){var k,t,u,s,v=function(b){Va(a,b.data.action,true)};k=0;for(t=d.length;k<t;k++){s=d[k];if(h.isArray(s)){u=h("<"+(s.DT_el||"div")+"/>").appendTo(b);r(u,s)}else{m=null;l="";switch(s){case "ellipsis":b.append('<span class="ellipsis">&#x2026;</span>');break;case "first":m=j.sFirst;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":m=j.sPrevious;l=s+(e>0?"":" "+
g.sPageButtonDisabled);break;case "next":m=j.sNext;l=s+(e<f-1?"":" "+g.sPageButtonDisabled);break;case "last":m=j.sLast;l=s+(e<f-1?"":" "+g.sPageButtonDisabled);break;default:m=s+1;l=e===s?g.sPageButtonActive:""}if(m!==null){u=h("<a>",{"class":g.sPageButton+" "+l,"aria-controls":a.sTableId,"aria-label":i[s],"data-dt-idx":p,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(m).appendTo(b);Ya(u,{action:s},v);p++}}}},t;try{t=h(b).find(H.activeElement).data("dt-idx")}catch(u){}r(h(b).empty(),
d);t!==k&&h(b).find("[data-dt-idx="+t+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return ab(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!cc.test(a))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||M(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return ab(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Sb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Sb(a,c,!0)?"html-num-fmt"+
c:null},function(a){return M(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return M(a)?a:"string"===typeof a?a.replace(Pb," ").replace(Ca,""):""},string:function(a){return M(a)?a:"string"===typeof a?a.replace(Pb," "):a}});var Ba=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Rb(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){return Date.parse(a)||-Infinity},
"html-pre":function(a){return M(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return M(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});fb("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]==
"asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("<div/>").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+
d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Zb=function(a){return"string"===typeof a?a.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):a};m.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Zb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):
"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Zb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Ob,_fnBuildAjax:ua,_fnAjaxUpdate:nb,_fnAjaxParameters:wb,_fnAjaxUpdateDraw:xb,_fnAjaxDataSrc:va,_fnAddColumn:Ga,_fnColumnOptions:la,_fnAdjustColumnSizing:Z,_fnVisibleToColumnIndex:$,_fnColumnIndexToVisible:aa,_fnVisbleColumns:ba,_fnGetColumns:na,_fnColumnTypes:Ia,_fnApplyColumnDefs:kb,_fnHungarianMap:Y,_fnCamelToHungarian:J,_fnLanguageCompat:Fa,
_fnBrowserDetect:ib,_fnAddData:N,_fnAddTr:oa,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:lb,_fnSplitObjNotation:La,_fnGetObjectDataFn:R,_fnSetObjectDataFn:S,_fnGetDataMaster:Ma,_fnClearTable:pa,_fnDeleteIndex:qa,_fnInvalidate:da,_fnGetRowElements:Ka,_fnCreateTr:Ja,_fnBuildHead:mb,_fnDrawHead:fa,_fnDraw:O,_fnReDraw:T,_fnAddOptionsHtml:pb,_fnDetectHeader:ea,
_fnGetUniqueThs:ta,_fnFeatureHtmlFilter:rb,_fnFilterComplete:ga,_fnFilterCustom:Ab,_fnFilterColumn:zb,_fnFilter:yb,_fnFilterCreateSearch:Ra,_fnEscapeRegex:Sa,_fnFilterData:Bb,_fnFeatureHtmlInfo:ub,_fnUpdateInfo:Eb,_fnInfoMacros:Fb,_fnInitialise:ha,_fnInitComplete:wa,_fnLengthChange:Ta,_fnFeatureHtmlLength:qb,_fnFeatureHtmlPaginate:vb,_fnPageChange:Va,_fnFeatureHtmlProcessing:sb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:tb,_fnScrollDraw:ma,_fnApplyToChildren:I,_fnCalculateColumnWidths:Ha,_fnThrottle:Qa,
_fnConvertToWidth:Gb,_fnGetWidestNode:Hb,_fnGetMaxLenString:Ib,_fnStringToCss:v,_fnSortFlatten:W,_fnSort:ob,_fnSortAria:Kb,_fnSortListener:Xa,_fnSortAttachListener:Oa,_fnSortingClasses:ya,_fnSortData:Jb,_fnSaveState:za,_fnLoadState:Lb,_fnSettingsFromNode:Aa,_fnLog:K,_fnMap:F,_fnBindAction:Ya,_fnCallbackReg:z,_fnCallbackFire:s,_fnLengthOverflow:Ua,_fnRenderer:Pa,_fnDataSource:y,_fnRowAttributes:Na,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=
m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<link rel='shortcut icon' type='image/x-icon' href='../favicon.ico' />
<script src="../libs/jquery.min.js"></script>
<script src="../libs/jquery.dataTables.min.js"></script>
<script src="../libs/handlebars.min.js"></script>
<script src="../libs/moment.min.js"></script>
<script src="../libs/handlebarsmoment.js"></script>
<script src="../bootstrap/bootstrap.min.js"></script>
<script src="../libs/bootstrap-notify.js"></script>
<link href="../bootstrap/bootstrap.min.css" rel="stylesheet">
<link href="../animate.css" rel="stylesheet">
<link href="../custom.css?changed=20200223" rel="stylesheet">
<title>Jackett</title>
</head>
<body>
<div id="page">
<img id="logo" src="../jacket_medium.png" /><span id="header-title">Jackett</span>
<hr />
<h1>Login</h1>
<form action="Dashboard" method="post">
<div class="input-area">
<span class="input-header">Admin password</span>
<input id="password" name="password" class="form-control input-right" type="password">
</div>
<div class="input-area">
<input type="submit" value="Login" />
</div>
</form>
</div>
</body>
</html>

View File

@@ -1,185 +0,0 @@
---
site: 0daykiev
name: 0day.kiev
description: "0day.kiev.ua is a RUSSIAN Private Torrent Tracker for MOVIES / TV / GENERAL"
language: ru-ru
type: private
encoding: windows-1251
links:
- https://tracker.0day.kiev.ua/
caps:
categorymappings:
- {id: 10, cat: Movies, desc: "Фильмы (Movies)"}
- {id: 11, cat: TV, desc: "Мультфильмы (Cartoons)"}
- {id: 29, cat: TV, desc: "Мультсериалы (TV Series)"}
- {id: 34, cat: TV/Anime, desc: "Аниме (Anime)"}
- {id: 20, cat: TV/Documentary, desc: "Документальное (Documentary)"}
- {id: 14, cat: Audio, desc: "Музыка / Аудио (Music / Audio)"}
- {id: 15, cat: Audio/Video, desc: "Музыка / Видео (Music / Video)"}
- {id: 16, cat: Movies/HD, desc: "HD / Фильмы (HD / Movies)"}
- {id: 27, cat: TV/HD, desc: "HD / Мультфильмы (HD / Cartoons)"}
- {id: 28, cat: TV/HD, desc: "HD / Документальное (HD / Documentary)"}
- {id: 41, cat: Movies/3D, desc: "HD / 3D видео (HD / 3D video)"}
- {id: 47, cat: Movies, desc: "HDv 0day Team"}
- {id: 17, cat: PC/Games, desc: "Игры / ПК (Games / PC)"}
- {id: 25, cat: Console/Xbox 360, desc: "Игры / XBOX360 (Games / XBOX360)"}
- {id: 33, cat: Console/PSP, desc: "Игры / PSP - PS2 (Games / PSP - PS2)"}
- {id: 37, cat: Console/PS3, desc: "Игры / PS3 (Games / PS3)"}
- {id: 18, cat: PC/0day, desc: "Софт / Windows (Software / Windows)"}
- {id: 39, cat: PC/Mac, desc: "Mac OS (Софт / Игры) (Mac OS (Software / Games))"}
- {id: 19, cat: TV, desc: "TV / Сериалы (TV shows)"}
- {id: 30, cat: TV/HD, desc: "HD / Сериалы (HD / TV Shows)"}
- {id: 23, cat: TV, desc: "TV / Передачи (TV / Broadcasts)"}
- {id: 22, cat: TV/Sport, desc: "Спорт (Sports)"}
- {id: 31, cat: Other, desc: "Прочее (Other)"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings:
- name: username
type: text
label: Username
- name: password
type: password
label: Password
- name: striprussian
type: checkbox
label: Strip Russian Letters
default: true
- name: sort
type: select
label: Sort requested from site
default: "4"
options:
"4": "created"
"7": "seeders"
"5": "size"
"1": "title"
- name: type
type: select
label: Order requested from site
default: "desc"
options:
"desc": "desc"
"asc": "asc"
login:
path: takelogin.php
method: post
inputs:
username: "{{ .Config.username }}"
password: "{{ .Config.password }}"
returnto: "/browse.php"
error:
- selector: div.maintitle:contains("Ошибка")
message:
selector: div.borderwrap table.embedded
test:
path: browse.php
selector: a[href="/logout.php"]
search:
paths:
# https://tracker.0day.kiev.ua/browse.php?c10=1&c27=1&search=endgame&incldead=1&where=0
- path: browse.php
keywordsfilters:
- name: diacritics
args: replace
- name: re_replace # S01 to Cезон 1
args: ["(?i)\\bS0*(\\d+)\\b", "езон $1"]
- name: re_replace # S01E01 to Сезон 1 Серии 1
args: ["(?i)\\bS0*(\\d+)E0*(\\d+)\\b", "езон $1 ерии $2"]
inputs:
$raw: "{{range .Categories}}c{{.}}=1&{{end}}"
search: "{{ .Keywords }}"
# 0 active 1 incldead 2 onlydead 3 gold 4 noseed 5 silver
incldead: 1
# 0 title 1 title and descr
where: 0
sort: "{{ .Config.sort}}"
type: "{{ .Config.type}}"
rows:
selector: table > tbody > tr.rowtorrentinfo
fields:
category:
selector: a[href^="browse.php?cat="]
attribute: href
filters:
- name: querystring
args: cat
title:
selector: a[href^="details.php?id="]
filters:
# normalize to SXXEYY format
- name: re_replace
args: ["[\\:\\-\\/\\|]", " "]
- name: replace
args: ["Кураж Бамбей", "kurazh"]
- name: replace
args: ["Кубик в Кубе", "Kubik"]
- name: replace
args: ["Кравец", "Kravec"]
- name: re_replace
args: ["(.*)\\([CСcс]езон\\s+(\\d+)\\)\\s+[CСcс]ери[ия]\\s+(\\d+)\\s+(\\d+)(.*)", "$1 S$2E$3-$4 rus $5"]
- name: re_replace
args: ["(.*)\\([CСcс]езон\\s+(\\d+)\\)(.*)", "$1 S$2 rus $3"]
- name: re_replace
args: ["(\\([А-Яа-яЁё\\W]+\\))|(^[А-Яа-яЁё\\W\\d]+\\/ )|([а-яА-ЯЁё \\-]+,+)|([а-яА-ЯЁё]+)", "{{ if .Config.striprussian }}{{ else }}$1$2$3$4{{ end }}"]
- name: replace
args: ["WEB DL", "WEBDL"]
- name: replace
args: ["WEBDLRip", "WEBDL"]
details:
selector: a[href^="details.php?id="]
attribute: href
download:
selector: a[href^="download.php?id="]
attribute: href
date:
selector: td:nth-child(2) i
filters:
- name: dateparse
args: "2006-01-02 15:04:05"
size:
selector: td:nth-child(4)
filters:
- name: replace
args: [".", ""]
- name: replace
args: [",", "."]
- name: replace
args: ["ТБ", "TB"]
- name: replace
args: ["ГБ", "GB"]
- name: replace
args: ["МБ", "MB"]
- name: replace
args: ["КБ", "KB"]
grabs:
selector: td:nth-child(5)
filters:
- name: regexp
args: (\d+)
seeders:
selector: td:nth-child(6)
filters:
- name: split
args: ["|", 0]
leechers:
selector: td:nth-child(6)
filters:
- name: split
args: ["|", 1]
downloadvolumefactor:
case:
img[src="pic/freedownload.gif"]: 0
img[src="pic/silverdownload.gif"]: 0.5
"*": 1
uploadvolumefactor:
text: 1
# engine n/a

View File

@@ -1,231 +0,0 @@
---
site: 1337x
name: 1337x
description: "1337X is a Public torrent site that offers verified torrent downloads"
language: en-us
type: public
encoding: UTF-8
links:
- https://1337x.to/
- https://1337x.gd/
- https://1337x.is/
- https://1337x.st/
- https://x1337x.ws/
- https://x1337x.eu/
- https://x1337x.se/
- https://1337x.unblocked.earth/
caps:
categorymappings:
#Anime
- {id: 28, cat: TV/Anime, desc: "Anime/Anime"}
- {id: 78, cat: TV/Anime, desc: "Anime/Dual Audio"}
- {id: 79, cat: TV/Anime, desc: "Anime/Dubbed"}
- {id: 80, cat: TV/Anime, desc: "Anime/Subbed"}
- {id: 81, cat: TV/Anime, desc: "Anime/Raw"}
#Audio
- {id: 22, cat: Audio/MP3, desc: "Music/MP3"}
- {id: 23, cat: Audio/Lossless, desc: "Music/Lossless"}
- {id: 24, cat: Audio, desc: "Music/DVD"}
- {id: 25, cat: Audio/Video, desc: "Music/Video"}
- {id: 26, cat: Audio, desc: "Music/Radio"}
- {id: 27, cat: Audio/Other, desc: "Music/Other"}
- {id: 53, cat: Audio, desc: "Music/Album"}
- {id: 58, cat: Audio, desc: "Music/Box set"}
- {id: 59, cat: Audio, desc: "Music/Discography"}
- {id: 60, cat: Audio, desc: "Music/Single"}
- {id: 68, cat: Audio, desc: "Music/Concerts"}
- {id: 69, cat: Audio, desc: "Music/AAC"}
#Movies
- {id: 1, cat: Movies/DVD, desc: "Movies/DVD"}
- {id: 2, cat: Movies/SD, desc: "Movies/Divx/Xvid"}
- {id: 3, cat: Movies, desc: "Movies/SVCD/VCD"}
- {id: 4, cat: Movies/Foreign, desc: "Movies/Dubs/Dual Audio"}
- {id: 42, cat: Movies/HD, desc: "Movies/HD"}
- {id: 54, cat: Movies/HD, desc: "Movies/h.264/x264"}
- {id: 55, cat: Movies, desc: "Movies/Mp4"}
- {id: 66, cat: Movies/3D, desc: "Movies/3D"}
- {id: 70, cat: Movies/HD, desc: "Movies/HEVC/x265"}
- {id: 73, cat: Movies, desc: "Movies/Bollywood"}
- {id: 76, cat: Movies/UHD, desc: "Movies/UHD"}
#TV
- {id: 5, cat: TV, desc: "TV/DVD"}
- {id: 6, cat: TV, desc: "TV/Divx/Xvid"}
- {id: 7, cat: TV, desc: "TV/SVCD/VCD"}
- {id: 41, cat: TV/HD, desc: "TV/HD"}
- {id: 71, cat: TV, desc: "TV/HEVC/x265"}
- {id: 74, cat: TV, desc: "TV/Cartoons"}
- {id: 75, cat: TV/SD, desc: "TV/SD"}
- {id: 9, cat: TV/Documentary, desc: "TV/Documentary"}
#Apps
- {id: 18, cat: PC, desc: "Apps/PC Software"}
- {id: 19, cat: PC/Mac, desc: "Apps/Mac"}
- {id: 20, cat: PC, desc: "Apps/Linux"}
- {id: 21, cat: PC, desc: "Apps/Other"}
- {id: 56, cat: PC/Phone-Android, desc: "Apps/Android"}
- {id: 57, cat: PC/Phone-IOS, desc: "Apps/iOS"}
#Games
- {id: 10, cat: PC/Games, desc: "Games/PC Game"}
- {id: 11, cat: Console/Other, desc: "Games/PS2"}
- {id: 12, cat: Console/PSP, desc: "Games/PSP"}
- {id: 13, cat: Console/Xbox, desc: "Games/Xbox"}
- {id: 14, cat: Console/Xbox 360, desc: "Games/Xbox360"}
- {id: 15, cat: Console/Other, desc: "Games/PS1"}
- {id: 16, cat: Console/Other, desc: "Games/Dreamcast"}
- {id: 17, cat: PC/Phone-Other, desc: "Games/Other"}
- {id: 43, cat: Console/PS3, desc: "Games/PS3"}
- {id: 44, cat: Console/Wii, desc: "Games/Wii"}
- {id: 45, cat: Console/NDS, desc: "Games/DS"}
- {id: 46, cat: Console, desc: "Games/GameCube"}
- {id: 72, cat: Console/3DS, desc: "Games/3DS"}
- {id: 77, cat: Console/PS4, desc: "Games/PS4"}
- {id: 82, cat: Console/Other, desc: "Games/Switch"}
#XXX
- {id: 48, cat: XXX/DVD, desc: "XXX/Video"}
- {id: 49, cat: XXX/Imageset, desc: "XXX/Picture"}
- {id: 50, cat: XXX, desc: "XXX/Magazine"}
- {id: 51, cat: XXX, desc: "XXX/Hentai"}
- {id: 67, cat: XXX, desc: "XXX/Games"}
#Other
- {id: 33, cat: Other, desc: "Other/Emulation"}
- {id: 34, cat: Books, desc: "Other/Tutorial"}
- {id: 35, cat: Other, desc: "Other/Sounds"}
- {id: 36, cat: Books/Ebook, desc: "Other/E-books"}
- {id: 37, cat: Other, desc: "Other/Images"}
- {id: 38, cat: Other, desc: "Other/Mobile Phone"}
- {id: 39, cat: Books/Comics, desc: "Other/Comics"}
- {id: 40, cat: Other/Misc, desc: "Other/Other"}
- {id: 47, cat: Other, desc: "Other/Nulled Script"}
- {id: 52, cat: Audio/Audiobook, desc: "Other/Audiobook"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
music-search: [q, album, artist, label, year]
settings:
- name: downloadlink
type: select
label: Download link
default: "magnet:"
options:
"http://itorrents.org/" : "iTorrents.org"
"http://torrage.info/" : "Torrage.info"
"http://btcache.me/" : "BTcache.me"
"magnet:": "magnet"
- name: sort
type: select
label: Sort requested from site
default: "time"
options:
"time": "created"
"seeders": "seeders"
"size": "size"
- name: type
type: select
label: Order requested from site
default: "desc"
options:
"desc": "desc"
"asc": "asc"
download:
# the .torrent url is on the on the details page
selector: ul li a[href^="{{ .Config.downloadlink }}"]
attribute: href
search:
paths:
# present first page of movies tv and music results if there are no search parms supplied (20 hits per page)
- path: "{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}sort-search{{else}}cat/Movies{{end}}{{if or (.Query.Album) (.Query.Artist) }}/{{ or (.Query.Album) (.Query.Artist) }}{{else}}/{{ .Keywords }}{{end}}{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}/{{else}}{{end}}{{ .Config.sort }}/{{ .Config.type }}/1/"
- path: "{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}sort-search{{else}}cat/TV{{end}}{{if or (.Query.Album) (.Query.Artist) }}/{{ or (.Query.Album) (.Query.Artist) }}{{else}}/{{ .Keywords }}{{end}}{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}/{{else}}{{end}}{{ .Config.sort }}/{{ .Config.type }}/{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}2{{else}}1{{end}}/"
- path: "{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}sort-search{{else}}cat/Music{{end}}{{if or (.Query.Album) (.Query.Artist) }}/{{ or (.Query.Album) (.Query.Artist) }}{{else}}/{{ .Keywords }}{{end}}{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}/{{else}}{{end}}{{ .Config.sort }}/{{ .Config.type }}/{{if or (.Query.Album) (.Query.Artist) (.Keywords) }}3{{else}}1{{end}}/"
keywordsfilters:
- name: replace # use this as a workaround till #893 is implemented
args: ["Greys Anatomy", "Grey's Anatomy"]
rows:
selector: tr:has(a[href^="/torrent/"])
fields:
title:
selector: td[class^="coll-1"] a[href^="/torrent/"]
filters:
- name: replace
args: ["Grey's Anatomy", "Greys Anatomy"]
- name: replace
args: ["\u000f", ""] # get rid of unwanted character
category:
optional: true
selector: td[class^="coll-1"] a[href^="/sub/"]
attribute: href
filters:
# extract the third part
- name: split
args: ["/", 2]
details:
selector: td[class^="coll-1"] a[href^="/torrent/"]
attribute: href
download:
# .torrent link is on the details page
selector: td[class^="coll-1"] a[href^="/torrent/"]
attribute: href
# dates come in three flavours:
date:
# (within this year) 7am Sep. 14th
optional: true
selector: td[class^="coll-date"]:not(:contains(":")):not(:contains("'"))
filters:
- name: replace
args: ["st", ""]
- name: replace
args: ["nd", ""]
- name: replace
args: ["rd", ""]
- name: replace
args: ["th", ""]
- name: dateparse
args: "3pm Jan. 2"
date:
# (more than a year ago) Apr. 18th '11
optional: true
selector: td[class^="coll-date"]:contains("'")
filters:
- name: replace
args: ["'", ""]
- name: replace
args: ["st", ""]
- name: replace
args: ["nd", ""]
- name: replace
args: ["rd", ""]
- name: replace
args: ["th", ""]
- name: dateparse
args: "Jan. 2 06"
date:
# (today) 12:25am
optional: true
selector: td[class^="coll-date"]:contains(":")
filters:
- name: dateparse
args: "3:04pm"
size:
selector: td[class^="coll-4"]
seeders:
selector: td[class^="coll-2"]
leechers:
selector: td[class^="coll-3"]
downloadvolumefactor:
text: 0
uploadvolumefactor:
text: 1
# engine n/a

View File

@@ -1,183 +0,0 @@
---
site: 2fast4you
name: 2 Fast 4 You
description: "2 Fast 4 You is a FRENCH Private site for TV / MOVIES / GENERAL"
language: fr-fr
type: private
encoding: UTF-8
links:
- https://2f4y.me/
legacylinks:
- http://www.2f4y.me/
- https://www.2f4y.me/
caps:
categorymappings:
- {id: 10, cat: TV/Anime, desc: "Animation: HD720P"}
- {id: 11, cat: TV/Anime, desc: "Animation: HD1080P"}
- {id: 56, cat: TV/Anime, desc: "Animation: DVDRip"}
- {id: 18, cat: PC/0day, desc: "Applications: PC"}
- {id: 16, cat: PC/Games, desc: "Applications: Jeux"}
- {id: 19, cat: PC/Phone-Android, desc: "Applications: Android"}
- {id: 17, cat: PC/0day, desc: "Applications: Autres"}
- {id: 67, cat: TV, desc: "Autres: Emission TV"}
- {id: 68, cat: TV/Sport, desc: "Autres: Sport"}
- {id: 40, cat: Other, desc: "Autres: Autres"}
- {id: 14, cat: TV/Documentary, desc: "Documentaires: DivX"}
- {id: 15, cat: TV/Documentary, desc: "Documentaires: HD"}
- {id: 76, cat: TV/Documentary, desc: "Documentaires: TVRip"}
- {id: 62, cat: Audio/Audiobook, desc: "E-Books: E-Books Audio"}
- {id: 50, cat: Books, desc: "E-Books: Manuel Français"}
- {id: 49, cat: Books, desc: "E-Books: Manuel Anglais"}
- {id: 36, cat: Books, desc: "E-Books: Livres Français"}
- {id: 53, cat: Books, desc: "E-Books: Livre Anglais"}
- {id: 52, cat: Books, desc: "E-Books: Revue - Journaux"}
- {id: 51, cat: Books, desc: "E-Books: BD"}
- {id: 95, cat: Movies, desc: "Films: Film Divx XviD"}
- {id: 66, cat: Movies, desc: "Films: VOSTFR"}
- {id: 71, cat: Movies/WEBDL, desc: "Films: WEB-DL"}
- {id: 65, cat: Movies, desc: "Films: VO"}
- {id: 72, cat: Movies/SD, desc: "Films: TVRip/HDTV"}
- {id: 70, cat: Movies/HD, desc: "Films: MHD X265"}
- {id: 57, cat: Movies/SD, desc: "Films: TS/CAM"}
- {id: 59, cat: Movies, desc: "Films: Spectacle"}
- {id: 55, cat: Movies/HD, desc: "Films: MHD 720P"}
- {id: 54, cat: Movies/HD, desc: "Films: MHD 1080P"}
- {id: 1, cat: Movies/HD, desc: "Films: HD720P"}
- {id: 2, cat: Movies/HD, desc: "Films: HD1080P"}
- {id: 90, cat: Movies/HD, desc: "Films: HD X265"}
- {id: 92, cat: Movies/HD, desc: "Films: 4K"}
- {id: 69, cat: Movies/3D, desc: "Films: Film 3D"}
- {id: 3, cat: Movies/DVD, desc: "Films: DVDRIP"}
- {id: 5, cat: Movies/DVD, desc: "Films: DVD9"}
- {id: 91, cat: Movies/HD, desc: "Films: RemuX"}
- {id: 89, cat: Movies/HD, desc: "Films: BD/BR Rip"}
- {id: 88, cat: Movies/BluRay, desc: "Films: Full BD/BR"}
- {id: 97, cat: Movies, desc: "Films: Cours Métrage"}
- {id: 79, cat: TV/Anime, desc: "Mangas: HD"}
- {id: 81, cat: TV/Anime, desc: "Mangas: HD VOSTFR"}
- {id: 85, cat: TV/Anime, desc: "Mangas: Web-DL"}
- {id: 86, cat: TV/Anime, desc: "Mangas: TV-RIP"}
- {id: 75, cat: Audio, desc: "Musique: Concert TVRip"}
- {id: 25, cat: Audio/MP3, desc: "Musique: Single MP3"}
- {id: 24, cat: Audio/Lossless, desc: "Musique: Single Flac"}
- {id: 22, cat: Audio/MP3, desc: "Musique: Album MP3"}
- {id: 23, cat: Audio/Lossless, desc: "Musique: Album Flac"}
- {id: 64, cat: Audio, desc: "Musique: Mégamix Maison"}
- {id: 96, cat: Audio/MP3, desc: "Musique: PlayList MP3"}
- {id: 94, cat: Audio, desc: "Musique: Podcast"}
- {id: 58, cat: Audio, desc: "Musique: Concert"}
- {id: 93, cat: TV, desc: "Serie TV: Saison VOSTFR"}
- {id: 61, cat: TV, desc: "Serie TV: Episode VOSTFR"}
- {id: 63, cat: TV, desc: "Serie TV: Episode VO"}
- {id: 12, cat: TV/Anime, desc: "Serie TV: Animation"}
- {id: 74, cat: TV, desc: "Serie TV: TVRip"}
- {id: 73, cat: TV/WEB-DL, desc: "Serie TV: WEB-DL"}
- {id: 7, cat: TV, desc: "Serie TV: Episode FR"}
- {id: 6, cat: TV, desc: "Serie TV: Saison FR"}
- {id: 98, cat: TV/Anime, desc: "Serie TV: Manga VOSTFR"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings:
- name: username
type: text
label: Username
- name: password
type: password
label: Password
- name: sort
type: select
label: Sort requested from site
default: "id"
options:
"id": "created"
"seeders": "seeders"
"size": "size"
"name": "title"
- name: order
type: select
label: Order requested from site
default: "desc"
options:
"desc": "desc"
"asc": "asc"
login:
path: account-login.php
method: post
inputs:
username: "{{ .Config.username }}"
password: "{{ .Config.password }}"
error:
- selector: form:contains("Erreur")
message:
selector: form
remove: table
test:
path: torrents-search.php
search:
paths:
- path: torrents-search.php
inputs:
$raw: "{{range .Categories}}c{{.}}=1&{{end}}"
search: "{{ .Keywords }}"
# 0 active 1 incldead 2 onlydead
incldead: 1
# 0 all 1 notfree 2 onlyfree
freeleech: 0
# 0 any 1 French 2 English 3 Multi 4-8 32-41
lang: 0
sort: "{{ .Config.sort}}"
order: "{{ .Config.order}}"
keywordsfilters:
- name: re_replace
args: ["^$", "%"] # replace empty search string with %
rows:
selector: table.ttable_headinner > tbody > tr[class^="t-row"]
fields:
category:
selector: a[href^="torrents.php?cat="]
attribute: href
filters:
- name: querystring
args: cat
download:
selector: a[href^="torrents-details.php?id="]
attribute: href
filters:
- name: replace
args: ["torrents-details.php", "download.php"]
title:
selector: a[href^="torrents-details.php?id="]
filters:
- name: replace
args: [" - (Nouveau!)", ""]
details:
selector: a[href^="torrents-details.php?id="]
attribute: href
banner:
selector: img.rounded-img
attribute: src
size:
selector: td:nth-child(5)
seeders:
selector: td:nth-child(7)
leechers:
selector: td:nth-child(8)
date:
text: now
downloadvolumefactor:
case:
img[title="freeleech"]: 0
"*": 1
uploadvolumefactor:
case:
"*": 1
# engine n/a

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