Compare commits

...

14 Commits

Author SHA1 Message Date
Garfield69
7b0adc7e45 torrentwal: gone. removed. resolves #7286 2020-03-15 16:35:05 +13:00
Diego Heras
d27ab11d8c elitetracker: add imdb search and fix categories (#7657) 2020-03-15 00:18:42 +01:00
Cory
5b6c9fee49 Fix proxy in all cases (#7631) resolves #7411
Co-authored-by: Diego Heras <ngosang@hotmail.es>
2020-03-14 17:53:16 -05:00
Garfield69
594959c858 torrent.lt: add config sort options
add movie-search
add freeleech
2020-03-15 11:08:20 +13:00
Garfield69
5b570b5cec torrentland: fix ULVF 2020-03-15 11:07:10 +13:00
Garfield69
875be5dde9 spiritofrevolution: fix imdbsearch. #4859 2020-03-15 08:59:11 +13:00
Garfield69
ffd1600226 bitturk, blutopia: update categories 2020-03-15 08:58:39 +13:00
Garfield69
07ef45b637 datascene: add imdb search support. #4859
also add config sort options
incldead
2020-03-15 08:58:02 +13:00
Cory
24f7fa461d bithdtv: improve imdb search. resolves #7596 (#7629) 2020-03-14 19:16:03 +01:00
Garfield69
8ebeb2bb17 icetorrent: fix imdbid searches. resolves #7651
also drop searching with both browse and browseadult
now use one or the other via config checkbox.
2020-03-15 06:33:08 +13:00
Diego Heras
fe3fcda356 style: improve date utils code style (#7632) 2020-03-15 05:05:10 +13:00
Diego Heras
b689b4581e funfile: fix parsing error. resolves #7633 (#7639) 2020-03-15 05:04:05 +13:00
Garfield69
623da8f70d readme: update net461 link 2020-03-14 21:30:06 +13:00
Garfield69
6afaf39d5a .gitattributes default eol=lf for all text source
used mainly by my win10 desktop github, it would pop up a warning that lf was going to be converting LF to CRLF
https://github.com/desktop/desktop/issues/3841 provided this solve
2020-03-14 21:29:43 +13:00
23 changed files with 553 additions and 631 deletions

View File

@@ -123,7 +123,7 @@ dotnet_style_prefer_compound_assignment=true:suggestion
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization=pascal_case
# Use PascalCase for constant fields
# 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
@@ -161,11 +161,11 @@ dotnet_naming_rule.asyncmethods_should_be_ends_with_async.style = ends_with_asyn
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.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_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
@@ -173,11 +173,11 @@ dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = stat
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.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.non_field_members.required_modifiers =
dotnet_naming_symbols.asyncmethods.applicable_kinds = delegate, method, local_function
dotnet_naming_symbols.asyncmethods.applicable_accessibilities = *
@@ -185,29 +185,29 @@ 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.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.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 = s_
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.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.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_prefix =
dotnet_naming_style.ends_with_async.required_suffix = Async
dotnet_naming_style.ends_with_async.word_separator =
dotnet_naming_style.ends_with_async.word_separator =
dotnet_naming_style.ends_with_async.capitalization = pascal_case
###############################

4
.gitattributes vendored
View File

@@ -1,15 +1,13 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
* text eol=lf
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
# Declare files that will always have LF line endings on checkout.
*.yml text eol=lf
*.sh text eol=lf
# Declare files that will always have CRLF line endings on checkout.
*.cs text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary

View File

@@ -18,7 +18,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
#### Supported Systems
* Windows 7SP1 or greater using .NET 4.6.1 or above [Download here](https://www.microsoft.com/net/framework/versions/net461)
* Windows 7SP1 or greater using .NET 4.6.1 or above [Download here](https://dotnet.microsoft.com/download/dotnet-framework/net461)
* 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
@@ -137,7 +137,6 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* Torrents.csv
* Torrentv
* TorrentView
* TorrentWal
* Torrentz2
* Underverse
* UnionDHT

View File

@@ -9,6 +9,10 @@
using System;
using System.Text.RegularExpressions;
// ReSharper disable NotAccessedField.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
namespace DateTimeRoutines
{
/// <summary>
@@ -21,11 +25,11 @@ namespace DateTimeRoutines
/// <summary>
/// Amount of seconds elapsed between 1970-01-01 00:00:00 and the date-time.
/// </summary>
/// <param name="date_time">date-time</param>
/// <param name="dateTime">date-time</param>
/// <returns>seconds</returns>
public static uint GetSecondsSinceUnixEpoch(this DateTime date_time)
public static uint GetSecondsSinceUnixEpoch(this DateTime dateTime)
{
var t = date_time - new DateTime(1970, 1, 1);
var t = dateTime - new DateTime(1970, 1, 1);
var ss = (int)t.TotalSeconds;
if (ss < 0)
return 0;
@@ -44,19 +48,19 @@ namespace DateTimeRoutines
/// <summary>
/// Index of first char of a date substring found in the string
/// </summary>
public readonly int IndexOfDate = -1;
public readonly int IndexOfDate;
/// <summary>
/// Length a date substring found in the string
/// </summary>
public readonly int LengthOfDate = -1;
public readonly int LengthOfDate;
/// <summary>
/// Index of first char of a time substring found in the string
/// </summary>
public readonly int IndexOfTime = -1;
public readonly int IndexOfTime;
/// <summary>
/// Length of a time substring found in the string
/// </summary>
public readonly int LengthOfTime = -1;
public readonly int LengthOfTime;
/// <summary>
/// DateTime found in the string
/// </summary>
@@ -82,45 +86,45 @@ namespace DateTimeRoutines
/// </summary>
public DateTime UtcDateTime;
internal ParsedDateTime(int index_of_date, int length_of_date, int index_of_time, int length_of_time, DateTime date_time)
internal ParsedDateTime(int indexOfDate, int lengthOfDate, int indexOfTime, int lengthOfTime, DateTime dateTime)
{
IndexOfDate = index_of_date;
LengthOfDate = length_of_date;
IndexOfTime = index_of_time;
LengthOfTime = length_of_time;
DateTime = date_time;
IsDateFound = index_of_date > -1;
IsTimeFound = index_of_time > -1;
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 index_of_date, int length_of_date, int index_of_time, int length_of_time, DateTime date_time, TimeSpan utc_offset)
internal ParsedDateTime(int indexOfDate, int lengthOfDate, int indexOfTime, int lengthOfTime, DateTime dateTime, TimeSpan utcOffset)
{
IndexOfDate = index_of_date;
LengthOfDate = length_of_date;
IndexOfTime = index_of_time;
LengthOfTime = length_of_time;
DateTime = date_time;
IsDateFound = index_of_date > -1;
IsTimeFound = index_of_time > -1;
UtcOffset = utc_offset;
IsUtcOffsetFound = Math.Abs(utc_offset.TotalHours) < 12;
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 (index_of_date < 0)//to avoid negative date exception when date is undefined
if (indexOfDate < 0)//to avoid negative date exception when date is undefined
{
var ts = date_time.TimeOfDay + utc_offset;
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 = date_time + utc_offset;
UtcDateTime = dateTime + utcOffset;
}
}
}
@@ -129,7 +133,7 @@ namespace DateTimeRoutines
/// 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
/// It is ignored if DefaultDateIsNow = true was set after DefaultDate
/// </summary>
public static DateTime DefaultDate
{
@@ -138,13 +142,7 @@ namespace DateTimeRoutines
_DefaultDate = value;
DefaultDateIsNow = false;
}
get
{
if (DefaultDateIsNow)
return DateTime.Now;
else
return _DefaultDate;
}
get => DefaultDateIsNow ? DateTime.Now : _DefaultDate;
}
private static DateTime _DefaultDate = DateTime.Now;
@@ -157,16 +155,17 @@ namespace DateTimeRoutines
/// <summary>
/// Defines default date-time format.
/// </summary>
[Flags]
public enum DateTimeFormat
{
/// <summary>
/// month number goes before day number
/// </summary>
USA_DATE,
UsaDate,
/// <summary>
/// day number goes before month number
/// </summary>
UK_DATE,
UkDate,
///// <summary>
///// time is specifed through AM or PM
///// </summary>
@@ -178,79 +177,79 @@ namespace DateTimeRoutines
#region parsing derived methods for DateTime output
/// <summary>
/// Tries to find date and time within the passed string and return it as DateTime structure.
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="date_time">parsed date-time output</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 default_format, out DateTime date_time)
public static bool TryParseDateTime(this string str, DateTimeFormat defaultFormat, out DateTime dateTime)
{
if (!TryParseDateTime(str, default_format, out ParsedDateTime parsed_date_time))
if (!TryParseDateTime(str, defaultFormat, out ParsedDateTime parsedDateTime))
{
date_time = new DateTime(1, 1, 1);
dateTime = new DateTime(1, 1, 1);
return false;
}
date_time = parsed_date_time.DateTime;
dateTime = parsedDateTime.DateTime;
return true;
}
/// <summary>
/// Tries to find date and/or time within the passed string and return it as DateTime structure.
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="date_time">parsed date-time output</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 default_format, out DateTime date_time)
public static bool TryParseDateOrTime(this string str, DateTimeFormat defaultFormat, out DateTime dateTime)
{
if (!TryParseDateOrTime(str, default_format, out ParsedDateTime parsed_date_time))
if (!TryParseDateOrTime(str, defaultFormat, out ParsedDateTime parsedDateTime))
{
date_time = new DateTime(1, 1, 1);
dateTime = new DateTime(1, 1, 1);
return false;
}
date_time = parsed_date_time.DateTime;
dateTime = parsedDateTime.DateTime;
return true;
}
/// <summary>
/// Tries to find time within the passed string and return it as DateTime structure.
/// 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="default_format">format to be used preferably in ambivalent instances</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 default_format, out DateTime time)
public static bool TryParseTime(this string str, DateTimeFormat defaultFormat, out DateTime time)
{
if (!TryParseTime(str, default_format, out var parsed_time, null))
if (!TryParseTime(str, defaultFormat, out var parsedTime, null))
{
time = new DateTime(1, 1, 1);
return false;
}
time = parsed_time.DateTime;
time = parsedTime.DateTime;
return true;
}
/// <summary>
/// Tries to find date within the passed string and return it as DateTime structure.
/// 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.
/// 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="default_format">format to be used preferably in ambivalent instances</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 default_format, out DateTime date)
public static bool TryParseDate(this string str, DateTimeFormat defaultFormat, out DateTime date)
{
if (!TryParseDate(str, default_format, out ParsedDateTime parsed_date))
if (!TryParseDate(str, defaultFormat, out ParsedDateTime parsedDate))
{
date = new DateTime(1, 1, 1);
return false;
}
date = parsed_date.DateTime;
date = parsedDate.DateTime;
return true;
}
@@ -259,69 +258,69 @@ namespace DateTimeRoutines
#region parsing derived methods for ParsedDateTime output
/// <summary>
/// Tries to find date and time within the passed string and return it as ParsedDateTime object.
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="parsed_date_time">parsed date-time output</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 default_format, out ParsedDateTime parsed_date_time)
public static bool TryParseDateTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedDateTime)
{
if (DateTimeRoutines.TryParseDateOrTime(str, default_format, out parsed_date_time)
&& parsed_date_time.IsDateFound
&& parsed_date_time.IsTimeFound
if (TryParseDateOrTime(str, defaultFormat, out parsedDateTime)
&& parsedDateTime.IsDateFound
&& parsedDateTime.IsTimeFound
)
return true;
parsed_date_time = null;
parsedDateTime = null;
return false;
}
/// <summary>
/// Tries to find time within the passed string and return it as ParsedDateTime object.
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="parsed_time">parsed date-time output</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 default_format, out ParsedDateTime parsed_time)
=> TryParseTime(str, default_format, out parsed_time, null);
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.
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="parsed_date_time">parsed date-time output</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 default_format, out ParsedDateTime parsed_date_time)
public static bool TryParseDateOrTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedDateTime)
{
parsed_date_time = null;
parsedDateTime = null;
ParsedDateTime parsed_time;
if (!TryParseDate(str, default_format, out
ParsedDateTime parsed_date))
ParsedDateTime parsedTime;
if (!TryParseDate(str, defaultFormat, out
ParsedDateTime parsedDate))
{
if (!TryParseTime(str, default_format, out parsed_time, null))
if (!TryParseTime(str, defaultFormat, out parsedTime, null))
return false;
var date_time = new DateTime(DefaultDate.Year, DefaultDate.Month, DefaultDate.Day, parsed_time.DateTime.Hour, parsed_time.DateTime.Minute, parsed_time.DateTime.Second);
parsed_date_time = new ParsedDateTime(-1, -1, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time, parsed_time.UtcOffset);
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, default_format, out parsed_time, parsed_date))
if (!TryParseTime(str, defaultFormat, out parsedTime, parsedDate))
{
var date_time = new DateTime(parsed_date.DateTime.Year, parsed_date.DateTime.Month, parsed_date.DateTime.Day, 0, 0, 0);
parsed_date_time = new ParsedDateTime(parsed_date.IndexOfDate, parsed_date.LengthOfDate, -1, -1, date_time);
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 date_time = new DateTime(parsed_date.DateTime.Year, parsed_date.DateTime.Month, parsed_date.DateTime.Day, parsed_time.DateTime.Hour, parsed_time.DateTime.Minute, parsed_time.DateTime.Second);
parsed_date_time = new ParsedDateTime(parsed_date.IndexOfDate, parsed_date.LengthOfDate, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time, parsed_time.UtcOffset);
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);
}
}
@@ -337,42 +336,39 @@ namespace DateTimeRoutines
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="parsed_time">parsed date-time output</param>
/// <param name="parsed_date">ParsedDateTime object if the date was found within this string, else NULL</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 default_format, out ParsedDateTime parsed_time, ParsedDateTime parsed_date)
public static bool TryParseTime(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedTime, ParsedDateTime parsedDate)
{
parsed_time = null;
parsedTime = null;
string time_zone_r;
if (default_format == DateTimeFormat.USA_DATE)
time_zone_r = @"(?:\s*(?'time_zone'UTC|GMT|CST|EST))?";
else
time_zone_r = @"(?:\s*(?'time_zone'UTC|GMT))?";
var timeZoneR = defaultFormat == DateTimeFormat.UsaDate ?
@"(?:\s*(?'time_zone'UTC|GMT|CST|EST))?" : @"(?:\s*(?'time_zone'UTC|GMT))?";
Match m;
if (parsed_date != null && parsed_date.IndexOfDate > -1)
if (parsedDate != null && parsedDate.IndexOfDate > -1)
{//look around the found date
//look for <date> hh:mm:ss <UTC offset>
m = Regex.Match(str.Substring(parsed_date.IndexOfDate + parsed_date.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);
//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(parsed_date.IndexOfDate + parsed_date.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))?" + time_zone_r + @"(?=$|[^\d\w])", RegexOptions.Compiled);
//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, parsed_date.IndexOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + time_zone_r + @"(?=$|[\s,]+)", RegexOptions.Compiled);
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(parsed_date.IndexOfDate, parsed_date.LengthOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + time_zone_r + @"(?=$|[\s,]+)", RegexOptions.Compiled);
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>
//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))?" + time_zone_r + @"(?=$|[^\d\w])", RegexOptions.Compiled);
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)
@@ -396,49 +392,49 @@ namespace DateTimeRoutines
return false;
}
if (string.Compare(m.Groups["ampm"].Value, "PM", true) == 0 && hour < 12)
if ("PM".Equals(m.Groups["ampm"].Value, StringComparison.OrdinalIgnoreCase) && hour < 12)
hour += 12;
else if (string.Compare(m.Groups["ampm"].Value, "AM", true) == 0 && hour == 12)
else if ("AM".Equals(m.Groups["ampm"].Value, StringComparison.OrdinalIgnoreCase) && hour == 12)
hour -= 12;
var date_time = new DateTime(1, 1, 1, hour, minute, second);
var dateTime = new DateTime(1, 1, 1, hour, minute, second);
if (m.Groups["offset_hh"].Success)
{
var offset_hh = int.Parse(m.Groups["offset_hh"].Value);
var offset_mm = 0;
var offsetHh = int.Parse(m.Groups["offset_hh"].Value);
var offsetMm = 0;
if (m.Groups["offset_mm"].Success)
offset_mm = int.Parse(m.Groups["offset_mm"].Value);
var utc_offset = new TimeSpan(offset_hh, offset_mm, 0);
offsetMm = int.Parse(m.Groups["offset_mm"].Value);
var utcOffset = new TimeSpan(offsetHh, offsetMm, 0);
if (m.Groups["offset_sign"].Value == "-")
utc_offset = -utc_offset;
parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time, utc_offset);
utcOffset = -utcOffset;
parsedTime = new ParsedDateTime(-1, -1, m.Index, m.Length, dateTime, utcOffset);
return true;
}
if (m.Groups["time_zone"].Success)
{
TimeSpan utc_offset;
TimeSpan utcOffset;
switch (m.Groups["time_zone"].Value)
{
case "UTC":
case "GMT":
utc_offset = new TimeSpan(0, 0, 0);
utcOffset = new TimeSpan(0, 0, 0);
break;
case "CST":
utc_offset = new TimeSpan(-6, 0, 0);
utcOffset = new TimeSpan(-6, 0, 0);
break;
case "EST":
utc_offset = new TimeSpan(-5, 0, 0);
utcOffset = new TimeSpan(-5, 0, 0);
break;
default:
throw new Exception("Time zone: " + m.Groups["time_zone"].Value + " is not defined.");
}
parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time, utc_offset);
parsedTime = new ParsedDateTime(-1, -1, m.Index, m.Length, dateTime, utcOffset);
return true;
}
parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time);
parsedTime = new ParsedDateTime(-1, -1, m.Index, m.Length, dateTime);
//}
//catch(Exception e)
//{
@@ -448,17 +444,17 @@ namespace DateTimeRoutines
}
/// <summary>
/// Tries to find date within the passed string and return it as ParsedDateTime object.
/// 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.
/// 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="default_format">format to be used preferably in ambivalent instances</param>
/// <param name="parsed_date">parsed date output</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 default_format, out ParsedDateTime parsed_date)
public static bool TryParseDate(this string str, DateTimeFormat defaultFormat, out ParsedDateTime parsedDate)
{
parsed_date = null;
parsedDate = null;
if (string.IsNullOrEmpty(str))
return false;
@@ -468,17 +464,17 @@ namespace DateTimeRoutines
if (m.Success)
{
DateTime date;
if ((default_format ^ DateTimeFormat.USA_DATE) == DateTimeFormat.USA_DATE)
if ((defaultFormat ^ DateTimeFormat.UsaDate) == DateTimeFormat.UsaDate)
{
if (!convert_to_date(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["day"].Value), int.Parse(m.Groups["month"].Value), out date))
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 (!convert_to_date(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out date))
if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out date))
return false;
}
parsed_date = new ParsedDateTime(m.Index, m.Length, -1, -1, date);
parsedDate = new ParsedDateTime(m.Index, m.Length, -1, -1, date);
return true;
}
@@ -486,9 +482,9 @@ namespace DateTimeRoutines
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 (!convert_to_date(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out var date))
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;
parsed_date = new ParsedDateTime(m.Index, m.Length, -1, -1, date);
parsedDate = new ParsedDateTime(m.Index, m.Length, -1, -1, date);
return true;
}
@@ -509,8 +505,8 @@ namespace DateTimeRoutines
if (m.Success)
{
var month = -1;
var index_of_date = m.Index;
var length_of_date = m.Length;
var indexOfDate = m.Index;
var lengthOfDate = m.Length;
switch (m.Groups["month"].Value)
{
@@ -563,22 +559,19 @@ namespace DateTimeRoutines
break;
}
int year;
if (!string.IsNullOrEmpty(m.Groups["year"].Value))
year = int.Parse(m.Groups["year"].Value);
else
year = DefaultDate.Year;
var year = !string.IsNullOrEmpty(m.Groups["year"].Value) ?
int.Parse(m.Groups["year"].Value) : DefaultDate.Year;
if (!convert_to_date(year, month, int.Parse(m.Groups["day"].Value), out var date))
if (!ConvertToDate(year, month, int.Parse(m.Groups["day"].Value), out var date))
return false;
parsed_date = new ParsedDateTime(index_of_date, length_of_date, -1, -1, date);
parsedDate = new ParsedDateTime(indexOfDate, lengthOfDate, -1, -1, date);
return true;
}
return false;
}
private static bool convert_to_date(int year, int month, int day, out DateTime date)
private static bool ConvertToDate(int year, int month, int day, out DateTime date)
{
if (year >= 100)
{

View File

@@ -20,6 +20,7 @@
- {id: 67, cat: XXX, desc: "XxX"}
- {id: 68, cat: Movies, desc: "Dual (TR-~)"}
- {id: 58, cat: Movies, desc: "Film"}
- {id: 72, cat: Movies, desc: "Belgesel"}
- {id: 60, cat: Movies/3D, desc: "3D"}
- {id: 45, cat: Movies, desc: "Eğitim / Prog "}
- {id: 1, cat: Movies, desc: "Filmler"}

View File

@@ -13,6 +13,8 @@
- {id: 1, cat: Movies, desc: "Movies"}
- {id: 2, cat: TV, desc: "TV"}
- {id: 3, cat: Movies, desc: "FANRES"}
- {id: 6, cat: TV/Anime, desc: "Anime"}
- {id: 7, cat: Movies/Other, desc: "Trailer"}
modes:
search: [q, imdbid]

View File

@@ -54,9 +54,33 @@
- {id: 12, cat: XXX, desc: "XxX"}
modes:
search: [q]
movie-search: [q]
tv-search: [q, season, ep]
search: [q, imdbid]
tv-search: [q, season, ep, imdbid]
movie-search: [q, imdbid]
settings:
- name: username
type: text
label: Username
- name: password
type: password
label: Password
- 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
@@ -68,7 +92,7 @@
- selector: td.embedded:has(h2:contains("failed"))
test:
path: browse.php
ratio:
path: browse.php
selector: font:contains("Ratio:") > span
@@ -77,9 +101,14 @@
paths:
- path: browse.php
inputs:
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
search: "{{ .Keywords }}"
incldead: 1
$raw: "{{ if .Categories}}{{ range .Categories }}c{{.}}=1&{{end}}{{else}}cat=0{{end}}"
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}"
# 1 active 2 incldead 3 onlydead 4 free
incldead: 2
# 0 name 1 genre 2 descr 3 imdb
blah: "{{ if .Query.IMDBID }}3{{else}}0{{end}}"
sort: "{{ .Config.sort }}"
type: "{{ .Config.type }}"
rows:
selector: div.ncls > table > tbody > tr:has(a.tname)

View File

@@ -77,6 +77,14 @@
# options:
# "DESC": "desc"
# "ASC": "asc"
- name: browseadult
type: checkbox
label: Use the BrowseAdult search engine
default: false
- name: info_browseadult
type: info
label: "About the BrowseAdult search engine"
default: "The regular <b>Browse</b> search engine does not return <i>Adult category</i> results.</br>The <b>BrowseAdult</b> search engine can return <i>all category</i> results, but without the <i>imdb tags</i>, and also does not support <i>imdbid</i> searches."
login:
path: login
@@ -97,15 +105,13 @@
search:
paths:
- path: browse.php
categorymappings: ["!", 9, 11, 58]
- path: browseadult.php
categorymappings: [9, 11, 58]
- path: "{{ if .Config.browseadult }}browseadult.php{{else}}browse.php{{end}}"
inputs:
$raw: "{{ range .Categories }}c{{.}}=1&{{end}}"
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}"
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}"
# 0 onlyalive 3 rosubbed 4 requested
incldead: 1
# name, descrname, genre, imdb
search_by: "{{ if .Query.IMDBID }}imdb{{else}}name{{end}}"
# by: "{{ .Config.sort }}"
# ord: "{{ .Config.type }}"

View File

@@ -108,7 +108,7 @@
- path: selection.php
inputs:
$raw: "{{ if .Categories }}{{ range .Categories }}scat[]={{.}}&{{end}}{{else}}{{end}}"
search: "{{ if .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}"
search: "{{ if .Query.IMDBID }}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}"
# 0 name 1 descr 2 both 4 imdb
blah: "{{ if .Query.IMDBID }}4{{else}}0{{end}}"
orderby: "{{ .Config.sort }}"

View File

@@ -195,12 +195,12 @@
- name: replace
args: ["f6c8a6", "0.75"]
uploadvolumefactor:
case:
img[src$="2x.gif"]: 2
img[src$="3x.gif"]: 3
img[src$="4x.gif"]: 4
img[src$="5x.gif"]: 5
img[src$="6x.gif"]: 6
img[src$="7x.gif"]: 7
"*": 1
case:
img[src$="2x.gif"]: 2
img[src$="3x.gif"]: 3
img[src$="4x.gif"]: 4
img[src$="5x.gif"]: 5
img[src$="6x.gif"]: 6
img[src$="7x.gif"]: 7
"*": 1
# xbtit customised

View File

@@ -1,7 +1,7 @@
---
site: torrentlt
name: Torrent.LT
description: "Torrent.LT is Private site for TV / MOVIES / GENERAL"
description: "Torrent.LT is a LITHUANIAN Private Torrent Tracker for 0DAY / GENERAL"
language: lt-lt
type: private
encoding: UTF-8
@@ -10,12 +10,14 @@
legacylinks:
- http://www.torrent.ai/
- https://torrent.ai/
caps:
categorymappings:
- {id: 27, cat: TV, desc: "Animacija"}
- {id: 76, cat: TV, desc: "Animacija / LT"}
- {id: 35, cat: TV/Anime, desc: "Anime"}
- {id: 31, cat: Movies/DVD, desc: "Filmai / DVD"}
- {id: 33, cat: Movies, desc: "Filmai / LTU"}
- {id: 33, cat: Movies, desc: "Filmai / LT"}
- {id: 43, cat: Movies, desc: "Filmai / LT-Subs"}
- {id: 34, cat: Movies, desc: "Filmai / Eng"}
- {id: 32, cat: Movies, desc: "Filmai / Rus"}
@@ -60,12 +62,12 @@
- {id: 71, cat: XXX/Packs, desc: "pr0n / pack"}
- {id: 30, cat: Other, desc: "Kita"}
- {id: 41, cat: Books, desc: "E-Books"}
- {id: 76, cat: TV, desc: "Animacija / LT"}
- {id: 77, cat: Other, desc: "Educational"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings:
- name: cookie
@@ -75,6 +77,21 @@
type: info
label: How to get the Cookie
default: "<ol><li>Login to this tracker in your browser<li>Open the <b>DevTools</b> panel by pressing <b>F12</b><li>Select the <b>Network</b> tab<li>Click on the <b>Doc</b> button<li>Refresh the page by pressing <b>F5</b><li>Select the <b>Headers</b> tab<li>Find 'cookie:' in the <b>Request Headers</b> section<li>Copy & paste the whole cookie string to here</ol>"
- name: sort
type: select
label: Sort requested from site
default: "0"
options:
"0": "created"
"6": "seeders"
"4": "size"
- name: type
type: select
label: Order requested from site
default: "desc"
options:
"desc": "desc"
"asc": "asc"
login:
method: cookie
@@ -87,16 +104,20 @@
paths:
- path: lt/torrents.php
inputs:
$raw: "{{range .Categories}}cats[]={{.}}&{{end}}"
$raw: "{{ range .Categories }}cats[]={{.}}&{{end}}"
search: "{{ .Keywords }}"
sort: "{{ .Config.sort }}"
type: "{{ .Config.type }}"
keywordsfilters:
- name: replace
args: [".", " "] # issue #3296
rows:
selector: table> tbody > tr[class^="torrents_table_row_"]
filters:
- name: andmatch
args: 50
fields:
title:
selector: td[class$="torrent_info"] a
@@ -122,7 +143,9 @@
size:
selector: td a.torrent_size
downloadvolumefactor:
text: 1
case:
img[src$="/freedownload.gif"]: 0
"*": 1
uploadvolumefactor:
text: 1
date:
@@ -131,4 +154,4 @@
filters:
- name: dateparse
args: "2006-01-02 15:04"
# engine tbd
# engine n/a

View File

@@ -1,87 +0,0 @@
---
site: torrentwal
name: TorrentWal (토렌트왈)
description: "Torrent Wal is a free Korean tracker for Korean media."
language: ko-KR
type: public
encoding: UTF-8
links:
- https://torrentwal.com/
legacylinks:
- https://torrentwal1.com/
- https://torrentwal2.com/
caps:
categorymappings:
- {id: "torrent_movie", cat: Movies, desc: "토렌트영화 (Movies)"}
- {id: "torrent_bluray", cat: Movies/BluRay, desc: "토렌트영화 (Movies)"}
- {id: "torrent_variety", cat: TV, desc: "TV예능 (TV Variety Shows)"}
- {id: "torrent_tv", cat: TV, desc: "TV드라마 (TV Dramas)"}
- {id: "torrent_docu", cat: TV/Documentary, desc: "다큐/시사 (Documentaries)"}
- {id: "torrent_sports", cat: TV/Sport, desc: "스포츠 (Sports)"}
- {id: "torrent_util", cat: PC, desc: "토렌트유틸 (Utilities)"}
- {id: "torrent_ani", cat: TV/Anime, desc: "애니메이션 (Anime)"}
- {id: "torrent_song", cat: Audio, desc: "해외음원 (Music)"}
- {id: "torrent_game", cat: PC/Games, desc: "토렌트게임 (Games)"}
- {id: "torrent_mid", cat: TV/FOREIGN, desc: 해외TV (Foreign TV)"}
- {id: "torrent_child", cat: TV, desc: "유아/어린이 (Children's)"}
- {id: "torrent_etc", cat: Other, desc: "토렌트 기타 (Other)"}
- {id: "torrent_iphone", cat: PC/Phone-Other, desc: "휴대기기 (Phone Apps)"}
- {id: "torrent_book", cat: Books, desc: "토렌트도서 (Books)"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings: []
search:
paths:
- path: "{{ if .Keywords }}bbs/s-1-{{ .Keywords }}{{else}}bbs/s-1-유희열{{end}}"
rows:
selector: tr.bg1:has(a[href^="/bbs/bc.php?bo_table="])
fields:
magnet:
selector: td:nth-child(1) a[href^="javascript:"]
attribute: href
filters:
- name: replace
args: ["javascript:Mag_dn('",""]
- name: replace
args: ["')",""]
- name: prepend
args: "magnet:?xt=urn:btih:"
seeders:
text: 1
leechers:
text: 1
category:
selector: td:nth-child(2) a[href^="/bbs/bc.php?bo_table="]
attribute: href
filters:
- name: querystring
args: bo_table
title:
selector: td:nth-child(2) a:last-of-type
details:
selector: td:nth-child(2) a:last-of-type
attribute: href
date:
selector: td:nth-child(3)
filters:
- name: dateparse
args: "01-02"
size:
selector: td:nth-child(4):contains(".M")
text: "0 "
size:
selector: td:nth-child(4):not(:contains(".M"))
optional: true
filters:
- name: append
args: "B"
downloadvolumefactor:
text: 0
uploadvolumefactor:
text: 1

View File

@@ -5,6 +5,7 @@ using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using AngleSharp.Html.Parser;
using Jackett.Common.Models;
using Jackett.Common.Models.IndexerConfig;
@@ -20,8 +21,7 @@ namespace Jackett.Common.Indexers
{
private string LoginUrl => SiteLink + "login.php";
private string TakeLoginUrl => SiteLink + "takelogin.php";
private string SearchUrl => SiteLink + "torrents.php?";
private string DownloadUrl => SiteLink + "download.php?id={0}";
private string SearchUrl => SiteLink + "torrents.php";
private new ConfigurationDataRecaptchaLogin configData
{
@@ -29,8 +29,9 @@ namespace Jackett.Common.Indexers
set => base.configData = value;
}
public BitHdtv(IIndexerConfigurationService configService, WebClient w, Logger l, IProtectionService ps)
: base(name: "BIT-HDTV",
public BitHdtv(IIndexerConfigurationService configService, WebClient w, Logger l, IProtectionService ps) :
base(
name: "BIT-HDTV",
description: "BIT-HDTV - Home of High Definition",
link: "https://www.bit-hdtv.com/",
caps: new TorznabCapabilities(),
@@ -43,9 +44,7 @@ namespace Jackett.Common.Indexers
Encoding = Encoding.GetEncoding("iso-8859-1");
Language = "en-us";
Type = "private";
TorznabCaps.SupportsImdbMovieSearch = true;
AddCategoryMapping(1, TorznabCatType.TVAnime); // Anime
AddCategoryMapping(2, TorznabCatType.MoviesBluRay); // Blu-ray
AddCategoryMapping(4, TorznabCatType.TVDocumentary); // Documentaries
@@ -76,13 +75,12 @@ namespace Jackett.Common.Indexers
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "g-recaptcha-response", configData.Captcha.Value },
var pairs = new Dictionary<string, string>
{
{"username", configData.Username.Value},
{"password", configData.Password.Value},
{"g-recaptcha-response", configData.Captcha.Value}
};
if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie))
{
// Cookie was manually supplied
@@ -92,7 +90,6 @@ namespace Jackett.Common.Indexers
var results = await PerformQuery(new TorznabQuery());
if (!results.Any())
throw new Exception("Your cookie did not work");
IsConfigured = true;
SaveConfig();
return IndexerConfigurationStatus.Completed;
@@ -104,17 +101,12 @@ namespace Jackett.Common.Indexers
}
}
var response = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs, null, true, null, SiteLink);
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () =>
var response = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs, null, true, referer: SiteLink);
await ConfigureIfOK(response.Cookies, response.Content?.Contains("logout.php") == true, () =>
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
var messageEl = dom.QuerySelectorAll("table.detail td.text").Last();
foreach (var child in messageEl.QuerySelectorAll("a"))
child.Remove();
foreach (var child in messageEl.QuerySelectorAll("style"))
child.Remove();
var errorMessage = messageEl.TextContent.Trim();
var errorMessage = dom.QuerySelector("table.detail td.text").FirstChild.TextContent.Trim();
throw new ExceptionWithConfigData(errorMessage, configData);
});
return IndexerConfigurationStatus.RequiresTesting;
@@ -123,95 +115,96 @@ namespace Jackett.Common.Indexers
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var qc = new NameValueCollection();
if (!string.IsNullOrWhiteSpace(query.ImdbID))
var results = new List<WebClientStringResult>();
var search = new UriBuilder(SearchUrl);
if (query.IsImdbQuery)
{
qc.Add("search", query.ImdbID);
qc.Add("options", "4");
qc.Add("options", "4"); //Search URL field for IMDB link
search.Query = qc.GetQueryString();
results.Add(await RequestStringWithCookiesAndRetry(search.ToString()));
qc["Options"] = "1"; //Search Title and Description
search.Query = qc.GetQueryString();
results.Add(await RequestStringWithCookiesAndRetry(search.ToString()));
}
else if (!string.IsNullOrWhiteSpace(query.GetQueryString()))
else
{
//Site handles empty string on search param. No need to check for IsNullOrEmpty()
qc.Add("search", query.GetQueryString());
qc.Add("options", "0");
qc.Add("options", "0"); //Search Title Only
search.Query = qc.GetQueryString();
results.Add(await RequestStringWithCookiesAndRetry(search.ToString()));
}
var searchUrl = SearchUrl + qc.GetQueryString();
var trackerCats = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true);
var results = await RequestStringWithCookiesAndRetry(searchUrl);
try
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(results.Content);
foreach (var child in dom.QuerySelectorAll("#needseed"))
child.Remove();
foreach (var table in dom.QuerySelectorAll("table[align=center] + br + table > tbody"))
var trackerCats = MapTorznabCapsToTrackers(query, true);
var parser = new HtmlParser();
foreach (var result in results)
try
{
var rows = table.Children;
foreach (var row in rows.Skip(1))
var dom = parser.ParseDocument(result.Content);
foreach (var child in dom.QuerySelectorAll("#needseed"))
child.Remove();
var table = dom.QuerySelector("table[align=center] + br + table > tbody");
foreach (var row in table.Children.Skip(1))
{
var release = new ReleaseInfo();
var qLink = row.Children[2].QuerySelector("a");
release.MinimumRatio = 1;
release.MinimumSeedTime = 172800; // 48 hours
release.Title = qLink.GetAttribute("title");
if (!query.MatchQueryStringAND(release.Title))
var detailsLink = new Uri(qLink.GetAttribute("href"));
//Skip irrelevant and duplicate entries
if (!query.MatchQueryStringAND(release.Title) || releases.Any(r => r.Guid == detailsLink))
continue;
release.Files = ParseUtil.CoerceLong(row.QuerySelector("td:nth-child(4)").TextContent);
release.Grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-child(8)").TextContent);
release.Guid = new Uri(qLink.GetAttribute("href"));
release.Files = ParseUtil.CoerceLong(row.Children[3].TextContent);
release.Grabs = ParseUtil.CoerceLong(row.Children[7].TextContent);
release.Guid = detailsLink;
release.Comments = release.Guid;
release.Link = new Uri(string.Format(DownloadUrl, qLink.GetAttribute("href").Split('=')[1]));
var catUrl = row.Children[1].FirstElementChild.GetAttribute("href");
var catNum = catUrl.Split('=', '&')[1];
release.Link = new Uri(SiteLink + row.QuerySelector("a[href^=\"download.php\"]").GetAttribute("href"));
var catUrl = new Uri(SiteLink + row.Children[1].FirstElementChild.GetAttribute("href"));
var catQuery = HttpUtility.ParseQueryString(catUrl.Query);
var catNum = catQuery["cat"];
release.Category = MapTrackerCatToNewznab(catNum);
// This tracker cannot search multiple cats at a time, so search all cats then filter out results from different cats
if (trackerCats.Count > 0 && !trackerCats.Contains(catNum))
// This tracker cannot search multiple cats at a time
// so search all cats then filter out results from different cats
if (trackerCats.Any() && !trackerCats.Contains(catNum))
continue;
var dateString = row.Children[5].TextContent.Trim();
var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture);
release.PublishDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Local);
var sizeStr = row.Children[6].TextContent;
release.Size = ReleaseInfo.GetBytes(sizeStr);
release.Seeders = ParseUtil.CoerceInt(row.Children[8].TextContent.Trim());
release.Peers = ParseUtil.CoerceInt(row.Children[9].TextContent.Trim()) + release.Seeders;
switch (row.GetAttribute("bgcolor"))
{
case "#DDDDDD":
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 2;
break;
case "#FFFF99":
release.DownloadVolumeFactor = 0;
release.UploadVolumeFactor = 1;
break;
case "#CCFF99":
release.DownloadVolumeFactor = 0;
release.UploadVolumeFactor = 2;
break;
default:
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 1;
break;
}
var bgcolor = row.GetAttribute("bgcolor");
if (bgcolor == "#DDDDDD")
{
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 2;
}
else if (bgcolor == "#FFFF99")
{
release.DownloadVolumeFactor = 0;
release.UploadVolumeFactor = 1;
}
else if (bgcolor == "#CCFF99")
{
release.DownloadVolumeFactor = 0;
release.UploadVolumeFactor = 2;
}
else
{
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 1;
}
releases.Add(release);
}
}
}
catch (Exception ex)
{
OnParseError(results.Content, ex);
}
catch (Exception ex)
{
OnParseError(result.Content, ex);
}
return releases;
}

View File

@@ -990,7 +990,7 @@ namespace Jackett.Common.Indexers
try
{
var Date = DateTimeUtil.ParseDateTimeGoLang(Data, layout);
Data = Date.ToString(DateTimeUtil.RFC1123ZPattern);
Data = Date.ToString(DateTimeUtil.Rfc1123ZPattern);
}
catch (FormatException ex)
{
@@ -1056,10 +1056,10 @@ namespace Jackett.Common.Indexers
break;
case "timeago":
case "reltime":
Data = DateTimeUtil.FromTimeAgo(Data).ToString(DateTimeUtil.RFC1123ZPattern);
Data = DateTimeUtil.FromTimeAgo(Data).ToString(DateTimeUtil.Rfc1123ZPattern);
break;
case "fuzzytime":
Data = DateTimeUtil.FromUnknown(Data).ToString(DateTimeUtil.RFC1123ZPattern);
Data = DateTimeUtil.FromUnknown(Data).ToString(DateTimeUtil.Rfc1123ZPattern);
break;
case "validfilename":
Data = StringUtil.MakeValidFileName(Data, '_', false);
@@ -1509,7 +1509,7 @@ namespace Jackett.Common.Indexers
break;
case "date":
release.PublishDate = DateTimeUtil.FromUnknown(value);
value = release.PublishDate.ToString(DateTimeUtil.RFC1123ZPattern);
value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern);
break;
case "files":
release.Files = ParseUtil.CoerceLong(value);

View File

@@ -16,21 +16,15 @@ using NLog;
namespace Jackett.Common.Indexers
{
// ReSharper disable once UnusedType.Global
internal class EliteTracker : BaseWebIndexer
{
private string LoginUrl => SiteLink + "takelogin.php";
private string BrowseUrl => SiteLink + "browse.php";
private bool TorrentHTTPSMode => configData.TorrentHTTPSMode.Value;
private string ReplaceMulti => configData.ReplaceMulti.Value;
private new ConfigurationDataEliteTracker configData
{
get => (ConfigurationDataEliteTracker)base.configData;
set => base.configData = value;
}
private new ConfigurationDataEliteTracker configData => (ConfigurationDataEliteTracker)base.configData;
public EliteTracker(IIndexerConfigurationService configService, WebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Elite-Tracker",
: base("Elite-Tracker",
description: "French Torrent Tracker",
link: "https://elite-tracker.net/",
caps: new TorznabCapabilities(),
@@ -45,97 +39,99 @@ namespace Jackett.Common.Indexers
Language = "fr-fr";
Type = "private";
// Clean capabilities
TorznabCaps.Categories.Clear();
TorznabCaps.SupportsImdbMovieSearch = true;
AddCategoryMapping(27, TorznabCatType.TVAnime, "Animation/Animes");
AddCategoryMapping(63, TorznabCatType.TVAnime, "Animes DVD");
AddCategoryMapping(56, TorznabCatType.TVAnime, "Animes HD");
AddCategoryMapping(59, TorznabCatType.TVAnime, "Animes Serie");
AddCategoryMapping(89, TorznabCatType.TVAnime, "Animes HDLight");
AddCategoryMapping(87, TorznabCatType.TVAnime, "Animes Pack");
AddCategoryMapping(88, TorznabCatType.TVAnime, "Animes SD");
AddCategoryMapping(90, TorznabCatType.TVAnime, "Animes 3D");
AddCategoryMapping(90, TorznabCatType.TVAnime, "Animes - 3D");
AddCategoryMapping(99, TorznabCatType.TVAnime, "Animes - 4K");
AddCategoryMapping(63, TorznabCatType.TVAnime, "Animes - DVD");
AddCategoryMapping(56, TorznabCatType.TVAnime, "Animes - HD");
AddCategoryMapping(89, TorznabCatType.TVAnime, "Animes - HDRip");
AddCategoryMapping(87, TorznabCatType.TVAnime, "Animes - Pack");
AddCategoryMapping(88, TorznabCatType.TVAnime, "Animes - SD");
AddCategoryMapping(59, TorznabCatType.TVAnime, "Animes - Serie");
AddCategoryMapping(3, TorznabCatType.PC0day, "APPLICATION");
AddCategoryMapping(74, TorznabCatType.PCPhoneAndroid, "ANDROID");
AddCategoryMapping(57, TorznabCatType.PCPhoneIOS, "IPHONE");
AddCategoryMapping(6, TorznabCatType.PC0day, "LINUX");
AddCategoryMapping(5, TorznabCatType.PCMac, "MAC");
AddCategoryMapping(4, TorznabCatType.PC0day, "WINDOWS");
AddCategoryMapping(74, TorznabCatType.PCPhoneAndroid, "APPLICATION - ANDROID");
AddCategoryMapping(57, TorznabCatType.PCPhoneIOS, "APPLICATION - IPHONE");
AddCategoryMapping(6, TorznabCatType.PC0day, "APPLICATION - LINUX");
AddCategoryMapping(5, TorznabCatType.PCMac, "APPLICATION - MAC");
AddCategoryMapping(4, TorznabCatType.PC0day, "APPLICATION - WINDOWS");
AddCategoryMapping(38, TorznabCatType.TVDocumentary, "DOCUMENTAIRES");
AddCategoryMapping(97, TorznabCatType.TVDocumentary, "DOCUMENTAIRES PACK");
AddCategoryMapping(97, TorznabCatType.TVDocumentary, "DOCUMENTAIRES - PACK");
AddCategoryMapping(34, TorznabCatType.Books, "EBOOKS");
AddCategoryMapping(86, TorznabCatType.Books, "ABOOKS");
AddCategoryMapping(86, TorznabCatType.Books, "EBOOKS - ABOOKS");
AddCategoryMapping(7, TorznabCatType.Movies, "FILMS");
AddCategoryMapping(11, TorznabCatType.MoviesDVD, "DVD");
AddCategoryMapping(10, TorznabCatType.MoviesSD, "DVD-RIP/BD-RIP");
AddCategoryMapping(53, TorznabCatType.MoviesSD, "DVD-SCREENER");
AddCategoryMapping(9, TorznabCatType.MoviesDVD, "R5");
AddCategoryMapping(8, TorznabCatType.MoviesSD, "SCREENER");
AddCategoryMapping(40, TorznabCatType.Movies, "VO");
AddCategoryMapping(39, TorznabCatType.Movies, "VOSTFR");
AddCategoryMapping(48, TorznabCatType.MoviesHD, "HD");
AddCategoryMapping(51, TorznabCatType.MoviesHD, "1080P");
AddCategoryMapping(70, TorznabCatType.Movies3D, "3D");
AddCategoryMapping(50, TorznabCatType.MoviesHD, "720P");
AddCategoryMapping(84, TorznabCatType.MoviesUHD, "4K");
AddCategoryMapping(49, TorznabCatType.MoviesBluRay, "BluRay");
AddCategoryMapping(78, TorznabCatType.MoviesHD, "HDLight");
AddCategoryMapping(85, TorznabCatType.MoviesHD, "x265");
AddCategoryMapping(91, TorznabCatType.Movies3D, "3D");
AddCategoryMapping(95, TorznabCatType.Movies, "VOSTFR");
AddCategoryMapping(48, TorznabCatType.MoviesHD, "FiLMS HD");
AddCategoryMapping(51, TorznabCatType.MoviesHD, "FiLMS HD - 1080p");
AddCategoryMapping(98, TorznabCatType.MoviesUHD, "FiLMS HD - 2160p");
AddCategoryMapping(70, TorznabCatType.Movies3D, "FiLMS HD - 3D");
AddCategoryMapping(84, TorznabCatType.MoviesUHD, "FiLMS HD - 4K");
AddCategoryMapping(50, TorznabCatType.MoviesHD, "FiLMS HD - 720P");
AddCategoryMapping(49, TorznabCatType.MoviesBluRay, "FiLMS HD - BluRay");
AddCategoryMapping(78, TorznabCatType.MoviesHD, "FiLMS HD - HDRip");
AddCategoryMapping(95, TorznabCatType.Movies, "FiLMS HD - VOSTFR");
AddCategoryMapping(85, TorznabCatType.MoviesHD, "FiLMS HD - x265");
AddCategoryMapping(7, TorznabCatType.Movies, "FiLMS SD");
AddCategoryMapping(91, TorznabCatType.Movies3D, "FiLMS SD - 3D");
AddCategoryMapping(11, TorznabCatType.MoviesDVD, "FiLMS SD - DVD");
AddCategoryMapping(53, TorznabCatType.MoviesSD, "FiLMS SD - DVD-SCREENER");
AddCategoryMapping(9, TorznabCatType.MoviesDVD, "FiLMS SD - R5");
AddCategoryMapping(8, TorznabCatType.MoviesSD, "FiLMS SD - SCREENER");
AddCategoryMapping(10, TorznabCatType.MoviesSD, "FiLMS SD - SDRip");
AddCategoryMapping(40, TorznabCatType.Movies, "FiLMS SD - VO");
AddCategoryMapping(39, TorznabCatType.Movies, "FiLMS SD - VOSTFR");
AddCategoryMapping(15, TorznabCatType.Console, "JEUX VIDEO");
AddCategoryMapping(76, TorznabCatType.Console3DS, "3DS");
AddCategoryMapping(18, TorznabCatType.ConsoleNDS, "DS");
AddCategoryMapping(55, TorznabCatType.PCPhoneIOS, "IPHONE");
AddCategoryMapping(80, TorznabCatType.PCGames, "LINUX");
AddCategoryMapping(79, TorznabCatType.PCMac, "OSX");
AddCategoryMapping(22, TorznabCatType.PCGames, "PC");
AddCategoryMapping(66, TorznabCatType.ConsolePS3, "PS2");
AddCategoryMapping(58, TorznabCatType.ConsolePS3, "PS3");
AddCategoryMapping(81, TorznabCatType.ConsolePS4, "PS4");
AddCategoryMapping(20, TorznabCatType.ConsolePSP, "PSP");
AddCategoryMapping(75, TorznabCatType.ConsolePS3, "PSX");
AddCategoryMapping(19, TorznabCatType.ConsoleWii, "WII");
AddCategoryMapping(83, TorznabCatType.ConsoleWiiU, "WiiU");
AddCategoryMapping(16, TorznabCatType.ConsoleXbox, "XBOX");
AddCategoryMapping(82, TorznabCatType.ConsoleXboxOne, "XBOX ONE");
AddCategoryMapping(17, TorznabCatType.ConsoleXbox360, "XBOX360");
AddCategoryMapping(44, TorznabCatType.ConsoleXbox360, "XBOX360.E");
AddCategoryMapping(54, TorznabCatType.ConsoleXbox360, "XBOX360.JTAG");
AddCategoryMapping(43, TorznabCatType.ConsoleXbox360, "XBOX360.NTSC");
AddCategoryMapping(96, TorznabCatType.Console, "NSW");
AddCategoryMapping(76, TorznabCatType.Console3DS, "JEUX VIDEO - 3DS");
AddCategoryMapping(18, TorznabCatType.ConsoleNDS, "JEUX VIDEO - DS");
AddCategoryMapping(55, TorznabCatType.PCPhoneIOS, "JEUX VIDEO - IPHONE");
AddCategoryMapping(80, TorznabCatType.PCGames, "JEUX VIDEO - LINUX");
AddCategoryMapping(96, TorznabCatType.ConsoleOther, "JEUX VIDEO - NSW");
AddCategoryMapping(79, TorznabCatType.PCMac, "JEUX VIDEO - OSX");
AddCategoryMapping(22, TorznabCatType.PCGames, "JEUX VIDEO - PC");
AddCategoryMapping(66, TorznabCatType.ConsolePS3, "JEUX VIDEO - PS2");
AddCategoryMapping(58, TorznabCatType.ConsolePS3, "JEUX VIDEO - PS3");
AddCategoryMapping(81, TorznabCatType.ConsolePS4, "JEUX VIDEO - PS4");
AddCategoryMapping(20, TorznabCatType.ConsolePSP, "JEUX VIDEO - PSP");
AddCategoryMapping(75, TorznabCatType.ConsolePS3, "JEUX VIDEO - PSX");
AddCategoryMapping(19, TorznabCatType.ConsoleWii, "JEUX VIDEO - WII");
AddCategoryMapping(83, TorznabCatType.ConsoleWiiU, "JEUX VIDEO - WiiU");
AddCategoryMapping(16, TorznabCatType.ConsoleXbox, "JEUX VIDEO - XBOX");
AddCategoryMapping(82, TorznabCatType.ConsoleXboxOne, "JEUX VIDEO - XBOX ONE");
AddCategoryMapping(17, TorznabCatType.ConsoleXbox360, "JEUX VIDEO - XBOX360");
AddCategoryMapping(23, TorznabCatType.Audio, "MUSIQUES");
AddCategoryMapping(26, TorznabCatType.Audio, "CLIP/CONCERT");
AddCategoryMapping(61, TorznabCatType.AudioLossless, "FLAC");
AddCategoryMapping(60, TorznabCatType.AudioMP3, "MP3");
AddCategoryMapping(26, TorznabCatType.Audio, "MUSIQUES - CLIP/CONCERT");
AddCategoryMapping(61, TorznabCatType.AudioLossless, "MUSIQUES - FLAC");
AddCategoryMapping(60, TorznabCatType.AudioMP3, "MUSIQUES - MP3");
AddCategoryMapping(30, TorznabCatType.TV, "SERIES");
AddCategoryMapping(73, TorznabCatType.TVSD, "Series Pack FR SD");
AddCategoryMapping(92, TorznabCatType.TVHD, "Series Pack FR HD");
AddCategoryMapping(93, TorznabCatType.TVSD, "Series Pack VOSTFR SD");
AddCategoryMapping(94, TorznabCatType.TVHD, "Series Pack VOSTFR HD");
AddCategoryMapping(31, TorznabCatType.TVSD, "Series FR SD");
AddCategoryMapping(32, TorznabCatType.TVSD, "Series VO SD");
AddCategoryMapping(33, TorznabCatType.TVSD, "Series VOSTFR SD");
AddCategoryMapping(77, TorznabCatType.TVSD, "Series DVD");
AddCategoryMapping(67, TorznabCatType.TVHD, "Series.FR HD");
AddCategoryMapping(68, TorznabCatType.TVHD, "Series VO HD");
AddCategoryMapping(69, TorznabCatType.TVHD, "Series VOSTFR HD");
AddCategoryMapping(77, TorznabCatType.TVSD, "SERIES - DVD");
AddCategoryMapping(100, TorznabCatType.TVUHD, "SERIES - 4k");
AddCategoryMapping(67, TorznabCatType.TVHD, "SERIES - FR HD");
AddCategoryMapping(31, TorznabCatType.TVSD, "SERIES - FR SD");
AddCategoryMapping(102, TorznabCatType.TVUHD, "SERIES - Pack 4k");
AddCategoryMapping(92, TorznabCatType.TVHD, "SERIES - Pack FR HD");
AddCategoryMapping(73, TorznabCatType.TVSD, "SERIES - Pack FR SD");
AddCategoryMapping(94, TorznabCatType.TVHD, "SERIES - Pack VOSTFR HD");
AddCategoryMapping(93, TorznabCatType.TVSD, "SERIES - Pack VOSTFR SD");
AddCategoryMapping(68, TorznabCatType.TVHD, "SERIES - VO HD");
AddCategoryMapping(32, TorznabCatType.TVSD, "SERIES - VO SD");
AddCategoryMapping(101, TorznabCatType.TVUHD, "SERIES - 4k");
AddCategoryMapping(69, TorznabCatType.TVHD, "SERIES - VOSTFR HD");
AddCategoryMapping(33, TorznabCatType.TVSD, "SERIES - VOSTFR SD");
AddCategoryMapping(47, TorznabCatType.TV, "SPECTACLES/EMISSIONS");
AddCategoryMapping(71, TorznabCatType.TV, "Emissions");
AddCategoryMapping(72, TorznabCatType.TV, "Spectacles");
AddCategoryMapping(71, TorznabCatType.TV, "SPECTACLES/EMISSIONS - Emissions");
AddCategoryMapping(72, TorznabCatType.TV, "SPECTACLES/EMISSIONS - Spectacles");
AddCategoryMapping(35, TorznabCatType.TVSport, "SPORT");
AddCategoryMapping(36, TorznabCatType.TVSport, "CATCH");
AddCategoryMapping(65, TorznabCatType.TVSport, "UFC");
AddCategoryMapping(36, TorznabCatType.TVSport, "SPORT - CATCH");
AddCategoryMapping(65, TorznabCatType.TVSport, "SPORT - UFC");
AddCategoryMapping(37, TorznabCatType.XXX, "XXX");
}
@@ -164,126 +160,116 @@ namespace Jackett.Common.Indexers
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var searchString = query.GetQueryString();
var queryCollection = new Dictionary<string, string>();
queryCollection.Add("search_type", "t_name");
queryCollection.Add("do", "search");
queryCollection.Add("keywords", searchString);
queryCollection.Add("category", "0"); // multi cat search not supported
var pairs = new Dictionary<string, string>
{
{"do", "search"},
{"search_type", !string.IsNullOrWhiteSpace(query.ImdbID) ? "t_genre" : "t_name"},
{"keywords", !string.IsNullOrWhiteSpace(query.ImdbID) ? query.ImdbID : query.GetQueryString()},
{"category", "0"} // multi cat search not supported
};
var results = await PostDataWithCookies(BrowseUrl, queryCollection);
var results = await PostDataWithCookies(BrowseUrl, pairs);
if (results.IsRedirect)
{
// re-login
await ApplyConfiguration(null);
results = await PostDataWithCookies(BrowseUrl, queryCollection);
results = await PostDataWithCookies(BrowseUrl, pairs);
}
try
{
var RowsSelector = "table[id='sortabletable'] > tbody > tr";
var SearchResultParser = new HtmlParser();
var SearchResultDocument = SearchResultParser.ParseDocument(results.Content);
var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector);
var lastDate = DateTime.Now;
foreach (var Row in Rows.Skip(1))
var parser = new HtmlParser();
var doc = parser.ParseDocument(results.Content);
var rows = doc.QuerySelectorAll("table[id='sortabletable'] > tbody > tr");
foreach (var row in rows.Skip(1))
{
var release = new ReleaseInfo();
release.MinimumRatio = 1;
release.MinimumSeedTime = 0;
var qTags = row.Children[1].QuerySelector("div:has(span[style=\"float: right;\"])");
if (qTags == null)
continue; // not a torrent line
var category = Row.QuerySelector("td:nth-child(1) > a");
var title = Row.QuerySelector("td:nth-child(2) a");
var added = Row.QuerySelector("td:nth-child(2) > div:has(span[style=\"float: right;\"])");
if (added == null) // not a torrent line
continue;
var pretime = added.QuerySelector("font.mkprettytime");
var tooltip = Row.QuerySelector("td:nth-child(2) > div.tooltip-content");
var cat = row.Children[0].QuerySelector("a").GetAttribute("href").Split('=')[1];
var title = row.Children[1].QuerySelector("a").TextContent;
var qLinks = row.Children[2].QuerySelectorAll("a");
var link = configData.TorrentHTTPSMode.Value ? qLinks[1].GetAttribute("href") : qLinks[0].GetAttribute("href");
var comments = row.Children[1].QuerySelector("a").GetAttribute("href");
var size = row.Children[4].TextContent;
var grabs = row.Children[5].QuerySelector("a").TextContent;
var seeders = row.Children[6].QuerySelector("a").TextContent;
var leechers = row.Children[7].QuerySelector("a").TextContent;
var link = Row.QuerySelector("td:nth-child(3)").QuerySelector("a");
var comments = Row.QuerySelector("td:nth-child(2)").QuerySelector("a");
var Size = Row.QuerySelector("td:nth-child(5)");
var Grabs = Row.QuerySelector("td:nth-child(6)").QuerySelector("a");
var Seeders = Row.QuerySelector("td:nth-child(7)").QuerySelector("a");
var Leechers = Row.QuerySelector("td:nth-child(8)").QuerySelector("a");
var dlVolumeFactor = 1.0;
if (qTags.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null)
dlVolumeFactor = 0.0;
else if (qTags.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null)
dlVolumeFactor = 0.5;
var categoryId = category.GetAttribute("href").Split('=')[1];
release.Category = MapTrackerCatToNewznab(categoryId);
var upVolumeFactor = qTags.QuerySelector("img[alt^=\"TORRENT X2\"]") != null ? 2.0 : 1.0;
release.Title = title.TextContent;
release.Category = MapTrackerCatToNewznab(categoryId);
release.Link = new Uri(link.GetAttribute("href"));
release.Comments = new Uri(comments.GetAttribute("href"));
var release = new ReleaseInfo
{
MinimumRatio = 1,
MinimumSeedTime = 0,
Category = MapTrackerCatToNewznab(cat),
Title = title,
Link = new Uri(link),
Comments = new Uri(comments),
Size = ReleaseInfo.GetBytes(size),
Seeders = ParseUtil.CoerceInt(seeders),
Grabs = ParseUtil.CoerceLong(grabs),
DownloadVolumeFactor = dlVolumeFactor,
UploadVolumeFactor = upVolumeFactor
};
release.Peers = ParseUtil.CoerceInt(leechers) + release.Seeders;
release.Guid = release.Link;
release.Size = ReleaseInfo.GetBytes(Size.TextContent);
release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent);
release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders;
release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent);
if (TorrentHTTPSMode)
var qTooltip = row.Children[1].QuerySelector("div.tooltip-content");
if (qTooltip != null)
{
var linkHttps = Row.QuerySelector("td:nth-child(4)").QuerySelector("a").GetAttribute("href");
var idTorrent = ParseUtil.GetArgumentFromQueryString(linkHttps, "id");
release.Link = new Uri($"{SiteLink}download.php?id={idTorrent}&type=ssl");
}
if (added.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null)
release.DownloadVolumeFactor = 0;
else if (added.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null)
release.DownloadVolumeFactor = 0.5;
else
release.DownloadVolumeFactor = 1;
if (added.QuerySelector("img[alt^=\"TORRENT X2\"]") != null)
release.UploadVolumeFactor = 2;
else
release.UploadVolumeFactor = 1;
if (tooltip != null)
{
var banner = tooltip.QuerySelector("img");
var banner = qTooltip.QuerySelector("img");
if (banner != null)
{
release.BannerUrl = new Uri(banner.GetAttribute("src"));
banner.Remove();
}
tooltip.QuerySelector("div:contains(\"Total Hits\")").Remove();
qTooltip.QuerySelector("div:contains(\"Total Hits\")").Remove();
var longtitle = tooltip.QuerySelectorAll("div").First();
release.Title = longtitle.TextContent;
longtitle.Remove();
var qLongTitle = qTooltip.QuerySelector("div");
release.Title = qLongTitle.TextContent;
qLongTitle.Remove();
var desc = tooltip.TextContent.Trim();
if (!string.IsNullOrWhiteSpace(desc))
release.Description = desc;
var description = qTooltip.TextContent.Trim();
if (!string.IsNullOrWhiteSpace(description))
release.Description = description;
}
//issue #5064 replace multi keyword
if (!string.IsNullOrEmpty(ReplaceMulti))
// issue #5064 replace multi keyword
if (!string.IsNullOrEmpty(configData.ReplaceMulti.Value))
{
var regex = new Regex("(?i)([\\.\\- ])MULTI([\\.\\- ])");
release.Title = regex.Replace(release.Title, "$1" + ReplaceMulti + "$2");
}
// issue #6855 Replace VOSTFR with ENGLISH
if (configData.Vostfr.Value)
{
release.Title = release.Title.Replace("VOSTFR", "ENGLISH");
release.Title = regex.Replace(release.Title, "$1" + configData.ReplaceMulti.Value + "$2");
}
if (pretime != null)
// issue #6855 Replace VOSTFR with ENGLISH
if (configData.Vostfr.Value)
release.Title = release.Title.Replace("VOSTFR", "ENGLISH");
var qPretime = qTags.QuerySelector("font.mkprettytime");
if (qPretime != null)
{
if (release.Description == null)
release.Description = pretime.TextContent;
release.Description = qPretime.TextContent;
else
release.Description += "<br>\n" + pretime.TextContent;
release.Description += "<br>\n" + qPretime.TextContent;
release.PublishDate = lastDate;
}
else
{
release.PublishDate = DateTime.ParseExact(added.TextContent.Trim(), "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture);
release.PublishDate = DateTime.ParseExact(qTags.TextContent.Trim(), "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture);
lastDate = release.PublishDate;
}

View File

@@ -78,11 +78,12 @@ namespace Jackett.Common.Indexers
{
var releases = new List<ReleaseInfo>();
var cats = MapTorznabCapsToTrackers(query);
var qc = new NameValueCollection
{
{"incldead", "1"},
{"showspam", "1"},
{"cat", MapTorznabCapsToTrackers(query).FirstOrDefault() ?? "0"}
{"cat", cats.Count == 1 ? cats[0] : "0"}
};
if (!string.IsNullOrWhiteSpace(query.GetQueryString()))
qc.Add("search", query.GetQueryString());

View File

@@ -2,18 +2,19 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
{
internal class ConfigurationDataEliteTracker : ConfigurationDataBasicLogin
{
public BoolItem TorrentHTTPSMode { get; private set; }
public DisplayItem PagesWarning { get; private set; }
public StringItem ReplaceMulti { get; private set; }
public BoolItem Vostfr { get; private set; }
public BoolItem TorrentHTTPSMode { get; }
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public DisplayItem PagesWarning { get; }
public StringItem ReplaceMulti { get; }
public BoolItem Vostfr { get; }
public ConfigurationDataEliteTracker()
: base()
{
TorrentHTTPSMode = new BoolItem { Name = "Use https for tracker URL", Value = false };
TorrentHTTPSMode = new BoolItem { Name = "Use HTTPS for tracker URL", Value = false };
PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Replace MULTI</b>, replace multi keyword in the resultset (leave empty to deactivate)</li><li><b>Replace VOSTFR with ENGLISH</b> lets you change the titles by replacing VOSTFR with ENGLISH.</li></ul>") { Name = "Preferences" };
ReplaceMulti = new StringItem() { Name = "Replace MULTI", Value = "MULTI.FRENCH" };
Vostfr = new BoolItem() { Name = "Replace VOSTFR with ENGLISH", Value = false };
ReplaceMulti = new StringItem { Name = "Replace MULTI", Value = "MULTI.FRENCH" };
Vostfr = new BoolItem { Name = "Replace VOSTFR with ENGLISH", Value = false };
}
}
}

View File

@@ -54,12 +54,9 @@ namespace Jackett.Common.Utils.Clients
public static void InitProxy(ServerConfig serverConfig)
{
// dispose old SocksWebProxy
if (webProxy != null && webProxy is SocksWebProxy)
{
((SocksWebProxy)webProxy).Dispose();
webProxy = null;
}
if (webProxy is SocksWebProxy proxy)
proxy.Dispose();
webProxy = null;
webProxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(webProxyUrl))
{

View File

@@ -61,12 +61,9 @@ namespace Jackett.Common.Utils.Clients
public static void InitProxy(ServerConfig serverConfig)
{
// dispose old SocksWebProxy
if (webProxy != null && webProxy is SocksWebProxy)
{
((SocksWebProxy)webProxy).Dispose();
webProxy = null;
}
if (webProxy is SocksWebProxy proxy)
proxy.Dispose();
webProxy = null;
webProxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(webProxyUrl))
{

View File

@@ -57,12 +57,9 @@ namespace Jackett.Common.Utils.Clients
public static void InitProxy(ServerConfig serverConfig)
{
// dispose old SocksWebProxy
if (webProxy != null && webProxy is SocksWebProxy)
{
((SocksWebProxy)webProxy).Dispose();
webProxy = null;
}
if (webProxy is SocksWebProxy proxy)
proxy.Dispose();
webProxy = null;
webProxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(webProxyUrl))
{

View File

@@ -53,12 +53,9 @@ namespace Jackett.Common.Utils.Clients
public static void InitProxy(ServerConfig serverConfig)
{
// dispose old SocksWebProxy
if (webProxy != null && webProxy is SocksWebProxy)
{
((SocksWebProxy)webProxy).Dispose();
webProxy = null;
}
if (webProxy is SocksWebProxy proxy)
proxy.Dispose();
webProxy = null;
webProxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(webProxyUrl))
{

View File

@@ -6,18 +6,26 @@ namespace Jackett.Common.Utils
{
public static class DateTimeUtil
{
public static string RFC1123ZPattern = "ddd, dd MMM yyyy HH':'mm':'ss z";
public const string Rfc1123ZPattern = "ddd, dd MMM yyyy HH':'mm':'ss z";
private static readonly Regex _TimeAgoRegexp = new Regex(@"(?i)\bago", RegexOptions.Compiled);
private static readonly Regex _TodayRegexp = new Regex(@"(?i)\btoday([\s,]*|$)", RegexOptions.Compiled);
private static readonly Regex _TomorrowRegexp = new Regex(@"(?i)\btomorrow([\s,]*|$)", RegexOptions.Compiled);
private static readonly Regex _YesterdayRegexp = new Regex(@"(?i)\byesterday([\s,]*|$)", RegexOptions.Compiled);
private static readonly Regex _DaysOfWeekRegexp = new Regex(@"(?i)\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\s+at\s+", RegexOptions.Compiled);
private static readonly Regex _MissingYearRegexp = new Regex(@"^(\d{1,2}-\d{1,2})(\s|$)", RegexOptions.Compiled);
private static readonly Regex _MissingYearRegexp2 = new Regex(@"^(\d{1,2}\s+\w{3})\s+(\d{1,2}\:\d{1,2}.*)$", RegexOptions.Compiled); // 1 Jan 10:30
public static DateTime UnixTimestampToDateTime(long unixTime)
{
var dt = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
var dt = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dt = dt.AddSeconds(unixTime).ToLocalTime();
return dt;
}
public static DateTime UnixTimestampToDateTime(double unixTime)
{
var unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
var unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond);
return new DateTime(unixStart.Ticks + unixTimeStampInTicks);
}
@@ -35,25 +43,21 @@ namespace Jackett.Common.Utils
{
str = str.ToLowerInvariant();
if (str.Contains("now"))
{
return DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local);
}
str = str.Replace(",", "");
str = str.Replace("ago", "");
str = str.Replace("and", "");
var timeAgo = TimeSpan.Zero;
var TimeagoRegex = new Regex(@"\s*?([\d\.]+)\s*?([^\d\s\.]+)\s*?");
var TimeagoMatches = TimeagoRegex.Match(str);
var timeagoRegex = new Regex(@"\s*?([\d\.]+)\s*?([^\d\s\.]+)\s*?");
var timeagoMatches = timeagoRegex.Match(str);
while (TimeagoMatches.Success)
while (timeagoMatches.Success)
{
var expanded = string.Empty;
var val = ParseUtil.CoerceFloat(TimeagoMatches.Groups[1].Value);
var unit = TimeagoMatches.Groups[2].Value;
TimeagoMatches = TimeagoMatches.NextMatch();
var val = ParseUtil.CoerceFloat(timeagoMatches.Groups[1].Value);
var unit = timeagoMatches.Groups[2].Value;
timeagoMatches = timeagoMatches.NextMatch();
if (unit.Contains("sec") || unit == "s")
timeAgo += TimeSpan.FromSeconds(val);
@@ -70,77 +74,37 @@ namespace Jackett.Common.Utils
else if (unit.Contains("year") || unit == "y")
timeAgo += TimeSpan.FromDays(val * 365);
else
{
throw new Exception("TimeAgo parsing failed, unknown unit: " + unit);
}
}
return DateTime.SpecifyKind(DateTime.Now - timeAgo, DateTimeKind.Local);
}
public static TimeSpan ParseTimeSpan(string time)
{
if (string.IsNullOrWhiteSpace(time))
return TimeSpan.Zero;
var offset = TimeSpan.Zero;
if (time.EndsWith("AM"))
{
time = time.Substring(0, time.Length - 2);
if (time.StartsWith("12")) // 12:15 AM becomes 00:15
time = "00" + time.Substring(2);
}
else if (time.EndsWith("PM"))
{
time = time.Substring(0, time.Length - 2);
offset = TimeSpan.FromHours(12);
}
var ts = TimeSpan.Parse(time);
ts += offset;
return ts;
}
// Uses the DateTimeRoutines library to parse the date
// http://www.codeproject.com/Articles/33298/C-Date-Time-Parser
public static DateTime FromFuzzyTime(string str, string format = null)
{
var dt_format = DateTimeRoutines.DateTimeRoutines.DateTimeFormat.USA_DATE;
if (format == "UK")
{
dt_format = DateTimeRoutines.DateTimeRoutines.DateTimeFormat.UK_DATE;
}
var dtFormat = format == "UK" ?
DateTimeRoutines.DateTimeRoutines.DateTimeFormat.UkDate :
DateTimeRoutines.DateTimeRoutines.DateTimeFormat.UsaDate;
if (DateTimeRoutines.DateTimeRoutines.TryParseDateOrTime(str, dt_format, out
DateTimeRoutines.DateTimeRoutines.ParsedDateTime dt))
{
if (DateTimeRoutines.DateTimeRoutines.TryParseDateOrTime(
str, dtFormat, out DateTimeRoutines.DateTimeRoutines.ParsedDateTime dt))
return dt.DateTime;
}
throw new Exception("FromFuzzyTime parsing failed");
}
public static Regex timeAgoRegexp = new Regex(@"(?i)\bago", RegexOptions.Compiled);
public static Regex todayRegexp = new Regex(@"(?i)\btoday([\s,]*|$)", RegexOptions.Compiled);
public static Regex tomorrowRegexp = new Regex(@"(?i)\btomorrow([\s,]*|$)", RegexOptions.Compiled);
public static Regex yesterdayRegexp = new Regex(@"(?i)\byesterday([\s,]*|$)", RegexOptions.Compiled);
public static Regex daysOfWeekRegexp = new Regex(@"(?i)\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\s+at\s+", RegexOptions.Compiled);
public static Regex missingYearRegexp = new Regex(@"^(\d{1,2}-\d{1,2})(\s|$)", RegexOptions.Compiled);
public static Regex missingYearRegexp2 = new Regex(@"^(\d{1,2}\s+\w{3})\s+(\d{1,2}\:\d{1,2}.*)$", RegexOptions.Compiled); // 1 Jan 10:30
public static DateTime FromUnknown(string str, string format = null)
{
try
{
str = ParseUtil.NormalizeSpace(str);
Match match;
if (str.ToLower().Contains("now"))
{
return DateTime.UtcNow;
}
// ... ago
match = timeAgoRegexp.Match(str);
var match = _TimeAgoRegexp.Match(str);
if (match.Success)
{
var timeago = str;
@@ -148,7 +112,7 @@ namespace Jackett.Common.Utils
}
// Today ...
match = todayRegexp.Match(str);
match = _TodayRegexp.Match(str);
if (match.Success)
{
var time = str.Replace(match.Groups[0].Value, "");
@@ -158,7 +122,7 @@ namespace Jackett.Common.Utils
}
// Yesterday ...
match = yesterdayRegexp.Match(str);
match = _YesterdayRegexp.Match(str);
if (match.Success)
{
var time = str.Replace(match.Groups[0].Value, "");
@@ -169,7 +133,7 @@ namespace Jackett.Common.Utils
}
// Tomorrow ...
match = tomorrowRegexp.Match(str);
match = _TomorrowRegexp.Match(str);
if (match.Success)
{
var time = str.Replace(match.Groups[0].Value, "");
@@ -180,14 +144,14 @@ namespace Jackett.Common.Utils
}
// [day of the week] at ... (eg: Saturday at 14:22)
match = daysOfWeekRegexp.Match(str);
match = _DaysOfWeekRegexp.Match(str);
if (match.Success)
{
var time = str.Replace(match.Groups[0].Value, "");
var dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified);
dt += ParseTimeSpan(time);
var dow = DayOfWeek.Monday;
DayOfWeek dow;
var groupMatchLower = match.Groups[1].Value.ToLower();
if (groupMatchLower.StartsWith("monday"))
dow = DayOfWeek.Monday;
@@ -221,28 +185,28 @@ namespace Jackett.Common.Utils
}
// add missing year
match = missingYearRegexp.Match(str);
match = _MissingYearRegexp.Match(str);
if (match.Success)
{
var date = match.Groups[1].Value;
var newDate = DateTime.Now.Year.ToString() + "-" + date;
var newDate = DateTime.Now.Year + "-" + date;
str = str.Replace(date, newDate);
}
// add missing year 2
match = missingYearRegexp2.Match(str);
match = _MissingYearRegexp2.Match(str);
if (match.Success)
{
var date = match.Groups[1].Value;
var time = match.Groups[2].Value;
str = date + " " + DateTime.Now.Year.ToString() + " " + time;
str = date + " " + DateTime.Now.Year + " " + time;
}
return FromFuzzyTime(str, format);
}
catch (Exception ex)
{
throw new Exception(string.Format("DateTime parsing failed for \"{0}\": {1}", str, ex.ToString()));
throw new Exception($"DateTime parsing failed for \"{str}\": {ex}");
}
}
@@ -319,8 +283,32 @@ namespace Jackett.Common.Utils
}
catch (FormatException ex)
{
throw new FormatException(string.Format("Error while parsing DateTime \"{0}\", using layout \"{1}\" ({2}): {3}", date, layout, pattern, ex.Message));
throw new FormatException($"Error while parsing DateTime \"{date}\", using layout \"{layout}\" ({pattern}): {ex.Message}");
}
}
private static TimeSpan ParseTimeSpan(string time)
{
if (string.IsNullOrWhiteSpace(time))
return TimeSpan.Zero;
var offset = TimeSpan.Zero;
if (time.EndsWith("AM"))
{
time = time.Substring(0, time.Length - 2);
if (time.StartsWith("12")) // 12:15 AM becomes 00:15
time = "00" + time.Substring(2);
}
else if (time.EndsWith("PM"))
{
time = time.Substring(0, time.Length - 2);
offset = TimeSpan.FromHours(12);
}
var ts = TimeSpan.Parse(time);
ts += offset;
return ts;
}
}
}

View File

@@ -372,6 +372,7 @@ namespace Jackett.Updater
"Definitions/torrentseeds.yml", // migrated to c#
"Definitions/torrentsmd.yml",
"Definitions/torrentvault.yml",
"Definitions/torrentwal.yml",
"Definitions/torrentwtf.yml",
"Definitions/torrof.yml",
"Definitions/torviet.yml",