diff --git a/src/CurlSharp/CurlSharp.csproj b/src/CurlSharp/CurlSharp.csproj index 4173495d8..849dc60ab 100644 --- a/src/CurlSharp/CurlSharp.csproj +++ b/src/CurlSharp/CurlSharp.csproj @@ -10,8 +10,6 @@ CurlSharp CurlSharp 512 - 12.0.0 - 2.0 true @@ -86,4 +84,14 @@ --> + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett.sln b/src/Jackett.sln index 850174ffe..eae7d18ea 100644 --- a/src/Jackett.sln +++ b/src/Jackett.sln @@ -1,5 +1,6 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 +# Visual Studio 2012 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett", "Jackett\Jackett.csproj", "{E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}" @@ -12,14 +13,49 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Release|Any CPU.Build.0 = Release|Any CPU {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|Any CPU.Build.0 = Debug|Any CPU {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|Any CPU.ActiveCfg = Release|Any CPU {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|Any CPU.Build.0 = Release|Any CPU + {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + Policies = $0 + $0.TextStylePolicy = $1 + $1.inheritsSet = VisualStudio + $1.inheritsScope = text/plain + $1.scope = text/x-csharp + $0.CSharpFormattingPolicy = $2 + $2.IndentSwitchBody = True + $2.IndentBlocksInsideExpressions = True + $2.AnonymousMethodBraceStyle = NextLine + $2.PropertyBraceStyle = NextLine + $2.PropertyGetBraceStyle = NextLine + $2.PropertySetBraceStyle = NextLine + $2.EventBraceStyle = NextLine + $2.EventAddBraceStyle = NextLine + $2.EventRemoveBraceStyle = NextLine + $2.StatementBraceStyle = NextLine + $2.ElseNewLinePlacement = NewLine + $2.CatchNewLinePlacement = NewLine + $2.FinallyNewLinePlacement = NewLine + $2.WhileNewLinePlacement = DoNotCare + $2.ArrayInitializerWrapping = DoNotChange + $2.ArrayInitializerBraceStyle = NextLine + $2.BeforeMethodDeclarationParentheses = False + $2.BeforeMethodCallParentheses = False + $2.BeforeConstructorDeclarationParentheses = False + $2.NewLineBeforeConstructorInitializerColon = NewLine + $2.NewLineAfterConstructorInitializerColon = SameLine + $2.BeforeDelegateDeclarationParentheses = False + $2.NewParentheses = False + $2.SpacesBeforeBrackets = False + $2.inheritsSet = Mono + $2.inheritsScope = text/x-csharp + $2.scope = text/x-csharp EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Jackett/CookieContainerExtensions.cs b/src/Jackett/CookieContainerExtensions.cs index 05bcfdc2e..447c3be30 100644 --- a/src/Jackett/CookieContainerExtensions.cs +++ b/src/Jackett/CookieContainerExtensions.cs @@ -5,29 +5,53 @@ using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; +using System.Web; namespace Jackett { - public static class CookieContainerExtensions - { - public static void FillFromJson (this CookieContainer cookies, Uri uri, JArray json) - { - foreach (string cookie in json) { + public static class CookieContainerExtensions + { - var w = cookie.Split ('='); - if (w.Length == 1) - cookies.Add (uri, new Cookie{ Name = cookie.Trim () }); - else - cookies.Add (uri, new Cookie (w [0].Trim (), w [1].Trim ())); - } - } + public static void FillFromJson(this CookieContainer cookies, Uri uri, JToken json) + { + if (json["cookies"] != null) + { + var cookieArray = (JArray)json["cookies"]; + foreach (string cookie in cookieArray) + { + var w = cookie.Split('='); + if (w.Length == 1) + { + cookies.Add(uri, new Cookie { Name = cookie.Trim() }); + } + else + { + cookies.Add(uri, new Cookie(w[0].Trim(), w[1].Trim())); + } + } + } - public static JArray ToJson (this CookieContainer cookies, Uri baseUrl) - { - return new JArray (( - from cookie in cookies.GetCookies (baseUrl).Cast () - select cookie.Name.Trim () + "=" + cookie.Value.Trim () - ).ToArray ()); - } - } + if (json["cookie_header"] != null) + { + var cfh = (string)json["cookie_header"]; + var cookieHeaders = ((string)json["cookie_header"]).Split(';'); + foreach (var c in cookieHeaders) + { + try + { + cookies.SetCookies(uri, c); + } + catch (CookieException ex) + { + Program.LoggerInstance.Info("(Non-critical) Problem loading cookie {0}, {1}, {2}", uri, c, ex.Message); + } + } + } + } + + public static void DumpToJson(this CookieContainer cookies, Uri uri, JToken json) + { + json["cookie_header"] = cookies.GetCookieHeader(uri); + } + } } diff --git a/src/Jackett/ExceptionWithConfigData.cs b/src/Jackett/ExceptionWithConfigData.cs index f65ecb8cc..0585b0db4 100644 --- a/src/Jackett/ExceptionWithConfigData.cs +++ b/src/Jackett/ExceptionWithConfigData.cs @@ -16,11 +16,4 @@ namespace Jackett ConfigData = data; } } - - public class CustomException : Exception - { - public CustomException(string message) - : base(message) - { } - } } diff --git a/src/Jackett/Indexers/AlphaRatio.cs b/src/Jackett/Indexers/AlphaRatio.cs index 3ff758bb5..1be0bf14d 100644 --- a/src/Jackett/Indexers/AlphaRatio.cs +++ b/src/Jackett/Indexers/AlphaRatio.cs @@ -75,16 +75,13 @@ namespace Jackett.Indexers public async Task ApplyConfiguration(JToken configJson) { - cookies = new CookieContainer(); - client = new HttpClient(handler); - var configSaveData = new JObject(); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); var config = new ConfigurationDataBasicLogin(); config.LoadValuesFromJson(configJson); - + var pairs = new Dictionary { { "username", config.Username.Value }, { "password", @config.Password.Value }, @@ -95,17 +92,18 @@ namespace Jackett.Indexers var content = new FormUrlEncodedContent(pairs); var message = CreateHttpRequest(new Uri(LoginUrl)); message.Content = content; - - //message.Headers.Referrer = new Uri(LoginUrl); + + //message.Headers.Referrer = new Uri(LoginUrl); string responseContent; - JArray cookieJArray; + + configSaveData = new JObject(); if (Program.IsWindows) { // If Windows use .net http var response = await client.SendAsync(message); responseContent = await response.Content.ReadAsStringAsync(); - cookieJArray = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); } else { @@ -113,7 +111,7 @@ namespace Jackett.Indexers var response = await CurlHelper.PostAsync(LoginUrl, pairs); responseContent = Encoding.UTF8.GetString(response.Content); cookieHeader = response.CookieHeader; - cookieJArray = new JArray(response.CookiesFlat); + configSaveData["cookie_header"] = cookieHeader; } if (!responseContent.Contains("logout.php?")) @@ -126,8 +124,6 @@ namespace Jackett.Indexers } else { - configSaveData = new JObject(); - configSaveData["cookies"] = cookieJArray; if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -146,7 +142,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(SiteLink, (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(SiteLink, jsonConfig); cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } diff --git a/src/Jackett/Indexers/AnimeBytes.cs b/src/Jackett/Indexers/AnimeBytes.cs index e368bb487..f271e28db 100644 --- a/src/Jackett/Indexers/AnimeBytes.cs +++ b/src/Jackett/Indexers/AnimeBytes.cs @@ -75,11 +75,11 @@ namespace Jackett.Indexers { var config = new ConfigurationDataBasicLoginAnimeBytes(); config.LoadValuesFromJson(configJson); - - + + // Get the login form as we need the CSRF Token var loginPage = await client.GetAsync(LoginUrl); - CQ loginPageDom = await loginPage.Content.ReadAsStringAsync(); + CQ loginPageDom = await loginPage.Content.ReadAsStringAsync(); var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last(); // Build login form @@ -131,9 +131,9 @@ namespace Jackett.Indexers { AllowRaws = config.IncludeRaw.Value; var configSaveData = new JObject(); - configSaveData["cookies"] = cookieContainer.ToJson(SiteLink); + cookieContainer.DumpToJson(SiteLink, configSaveData); configSaveData["raws"] = AllowRaws; - + if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -143,7 +143,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookieContainer.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookieContainer.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; AllowRaws = jsonConfig["raws"].Value(); } @@ -198,9 +198,10 @@ namespace Jackett.Indexers return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); } - var queryUrl = SearchUrl; + var queryUrl = SearchUrl; // Only include the query bit if its required as hopefully the site caches the non query page - if(!string.IsNullOrWhiteSpace(query.SearchTerm)){ + if (!string.IsNullOrWhiteSpace(query.SearchTerm)) + { queryUrl += "&action=advanced&search_type=title&sort=time_added&way=desc&anime%5Btv_series%5D=1&searchstr=" + WebUtility.UrlEncode(query.SearchTerm); } @@ -229,8 +230,8 @@ namespace Jackett.Indexers var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim(); int yearIndex = yearStr.LastIndexOf("["); if (yearIndex > -1) - yearStr = yearStr.Substring(yearIndex+1); - + yearStr = yearStr.Substring(yearIndex + 1); + int year = 0; if (!int.TryParse(yearStr, out year)) year = DateTime.Now.Year; @@ -301,7 +302,7 @@ namespace Jackett.Indexers var downloadLink = links.Get(0); release.Guid = new Uri(BaseUrl + "/" + downloadLink.Attributes.GetAttribute("href") + "&nh=" + Hash(title)); // Sonarr should dedupe on this url - allow a url per name. release.Link = release.Guid;// We dont know this so try to fake based on the release year - release.PublishDate = new DateTime(year,1,1); + release.PublishDate = new DateTime(year, 1, 1); release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1); var infoLink = links.Get(1); @@ -347,15 +348,15 @@ namespace Jackett.Indexers if (size.Count() > 0) { var sizeParts = size.First().Text().Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeParts[1], float.Parse(sizeParts[0])); + release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); } // Additional 5 hours per GB release.MinimumSeedTime += (release.Size / 1000000000) * 18000; // Peer info - release.Seeders = int.Parse(rowCq.Find(".torrent_seeders").Text()); - release.Peers = release.Seeders + int.Parse(rowCq.Find(".torrent_leechers").Text()); + release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text()); releases.Add(release); } @@ -369,7 +370,7 @@ namespace Jackett.Indexers throw ex; } - + // Add to the cache lock (cache) { diff --git a/src/Jackett/Indexers/BitHdtv.cs b/src/Jackett/Indexers/BitHdtv.cs index a3669d8de..fc16b16f9 100644 --- a/src/Jackett/Indexers/BitHdtv.cs +++ b/src/Jackett/Indexers/BitHdtv.cs @@ -86,7 +86,7 @@ namespace Jackett.Indexers else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -101,7 +101,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -137,15 +137,15 @@ namespace Jackett.Indexers var dateString = qRow.Children().ElementAt(5).Cq().Text().Trim(); var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - release.PublishDate = pubDate; + release.PublishDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Local); var sizeCol = qRow.Children().ElementAt(6); var sizeVal = sizeCol.ChildNodes[0].NodeValue; var sizeUnit = sizeCol.ChildNodes[2].NodeValue; - release.Size = ReleaseInfo.GetBytes(sizeUnit, float.Parse(sizeVal)); + release.Size = ReleaseInfo.GetBytes(sizeUnit, ParseUtil.CoerceFloat(sizeVal)); - release.Seeders = int.Parse(qRow.Children().ElementAt(8).Cq().Text().Trim(), NumberStyles.AllowThousands); - release.Peers = int.Parse(qRow.Children().ElementAt(9).Cq().Text().Trim(), NumberStyles.AllowThousands) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(qRow.Children().ElementAt(8).Cq().Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Children().ElementAt(9).Cq().Text().Trim()) + release.Seeders; releases.Add(release); } diff --git a/src/Jackett/Indexers/BitMeTV.cs b/src/Jackett/Indexers/BitMeTV.cs index 3df784016..109ff8c03 100644 --- a/src/Jackett/Indexers/BitMeTV.cs +++ b/src/Jackett/Indexers/BitMeTV.cs @@ -111,7 +111,7 @@ namespace Jackett else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -122,7 +122,7 @@ namespace Jackett public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -163,17 +163,18 @@ namespace Jackett var timeParts = new List(timestamp.Replace(" at", "").Replace(",", "").Split(' ')); timeParts[2] = Regex.Replace(timeParts[2], "[^0-9.]", ""); var formattedTimeString = string.Join(" ", timeParts.ToArray()).Trim(); - release.PublishDate = DateTime.ParseExact(formattedTimeString, "dddd MMMM d yyyy hh:mm:ss tt", CultureInfo.InvariantCulture); + var date = DateTime.ParseExact(formattedTimeString, "dddd MMMM d yyyy hh:mm:ss tt", CultureInfo.InvariantCulture); + release.PublishDate = DateTime.SpecifyKind(date, DateTimeKind.Utc).ToLocalTime(); release.Link = new Uri(BaseUrl + "/" + row.ChildElements.ElementAt(2).Cq().Children("a.index").Attr("href")); var sizeCol = row.ChildElements.ElementAt(6); - var sizeVal = float.Parse(sizeCol.ChildNodes[0].NodeValue); + var sizeVal = ParseUtil.CoerceFloat(sizeCol.ChildNodes[0].NodeValue); var sizeUnit = sizeCol.ChildNodes[2].NodeValue; release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); - release.Seeders = int.Parse(row.ChildElements.ElementAt(8).Cq().Text(), NumberStyles.AllowThousands); - release.Peers = int.Parse(row.ChildElements.ElementAt(9).Cq().Text(), NumberStyles.AllowThousands) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders; //if (!release.Title.ToLower().Contains(title.ToLower())) // continue; diff --git a/src/Jackett/Indexers/Freshon.cs b/src/Jackett/Indexers/Freshon.cs index be4cbda66..37bbde239 100644 --- a/src/Jackett/Indexers/Freshon.cs +++ b/src/Jackett/Indexers/Freshon.cs @@ -90,7 +90,7 @@ namespace Jackett else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -101,7 +101,7 @@ namespace Jackett public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -164,11 +164,11 @@ namespace Jackett pubDate = DateTime.ParseExact(dateString, "d-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); release.PublishDate = pubDate; - release.Seeders = int.Parse(qRow.Find("td.table_seeders").Text().Trim(), NumberStyles.AllowThousands); - release.Peers = int.Parse(qRow.Find("td.table_leechers").Text().Trim(), NumberStyles.AllowThousands) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td.table_seeders").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Find("td.table_leechers").Text().Trim()) + release.Seeders; var sizeCol = qRow.Find("td.table_size")[0]; - var sizeVal = float.Parse(sizeCol.ChildNodes[0].NodeValue.Trim()); + var sizeVal = ParseUtil.CoerceFloat(sizeCol.ChildNodes[0].NodeValue.Trim()); var sizeUnit = sizeCol.ChildNodes[2].NodeValue.Trim(); release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); diff --git a/src/Jackett/Indexers/HDTorrents.cs b/src/Jackett/Indexers/HDTorrents.cs index 8a96354e6..1495cf197 100644 --- a/src/Jackett/Indexers/HDTorrents.cs +++ b/src/Jackett/Indexers/HDTorrents.cs @@ -92,7 +92,9 @@ namespace Jackett.Indexers { "uid", config.Username.Value }, { "pwd", config.Password.Value } }; + var content = new FormUrlEncodedContent(pairs); + var loginRequest = CreateHttpRequest(LoginUrl); loginRequest.Method = HttpMethod.Post; loginRequest.Content = content; @@ -103,14 +105,13 @@ namespace Jackett.Indexers if (!responseContent.Contains("If your browser doesn't have javascript enabled")) { - CQ dom = responseContent; var errorMessage = "Couldn't login"; throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); } else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -121,7 +122,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(DefaultUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(SiteLink, jsonConfig); IsConfigured = true; } diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs index 450f29e51..a5c0de73f 100644 --- a/src/Jackett/Indexers/IPTorrents.cs +++ b/src/Jackett/Indexers/IPTorrents.cs @@ -89,7 +89,7 @@ namespace Jackett.Indexers else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -110,7 +110,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -151,7 +151,7 @@ namespace Jackett.Indexers var descString = qRow.Find(".t_ctime").Text(); var dateString = descString.Split('|').Last().Trim(); dateString = dateString.Split(new string[] { " by " }, StringSplitOptions.None)[0]; - var dateValue = float.Parse(dateString.Split(' ')[0]); + var dateValue = ParseUtil.CoerceFloat(dateString.Split(' ')[0]); var dateUnit = dateString.Split(' ')[1]; if (dateUnit.Contains("minute")) pubDate = DateTime.Now - TimeSpan.FromMinutes(dateValue); @@ -173,12 +173,12 @@ namespace Jackett.Indexers release.Link = new Uri(BaseUrl + qLink.Attr("href")); var sizeStr = row.ChildElements.ElementAt(5).Cq().Text().Trim(); - var sizeVal = float.Parse(sizeStr.Split(' ')[0]); + var sizeVal = ParseUtil.CoerceFloat(sizeStr.Split(' ')[0]); var sizeUnit = sizeStr.Split(' ')[1]; release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); - release.Seeders = int.Parse(qRow.Find(".t_seeders").Text().Trim(), NumberStyles.AllowThousands); - release.Peers = int.Parse(qRow.Find(".t_leechers").Text().Trim(), NumberStyles.AllowThousands) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".t_seeders").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".t_leechers").Text().Trim()) + release.Seeders; releases.Add(release); } diff --git a/src/Jackett/Indexers/MoreThanTV.cs b/src/Jackett/Indexers/MoreThanTV.cs index d9fb0ee13..a05c7ae9f 100644 --- a/src/Jackett/Indexers/MoreThanTV.cs +++ b/src/Jackett/Indexers/MoreThanTV.cs @@ -86,14 +86,16 @@ namespace Jackett.Indexers var content = new FormUrlEncodedContent(pairs); string responseContent; - JArray cookieJArray; + + var configSaveData = new JObject(); if (Program.IsWindows) { // If Windows use .net http var response = await client.PostAsync(LoginUrl, content); responseContent = await response.Content.ReadAsStringAsync(); - cookieJArray = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); + } else { @@ -101,7 +103,7 @@ namespace Jackett.Indexers var response = await CurlHelper.PostAsync(LoginUrl, pairs); responseContent = Encoding.UTF8.GetString(response.Content); cookieHeader = response.CookieHeader; - cookieJArray = new JArray(response.CookiesFlat); + configSaveData["cookie_header"] = cookieHeader; } if (!responseContent.Contains("logout.php?")) @@ -114,9 +116,6 @@ namespace Jackett.Indexers } else { - - var configSaveData = new JObject(); - configSaveData["cookies"] = cookieJArray; if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -126,7 +125,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(SiteLink, (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(SiteLink, jsonConfig); cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } @@ -171,7 +170,10 @@ namespace Jackett.Indexers DateTime pubDate = DateTime.MinValue; double dateNum; if (double.TryParse((string)r["groupTime"], out dateNum)) + { pubDate = UnixTimestampToDateTime(dateNum); + pubDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Utc).ToLocalTime(); + } var groupName = (string)r["groupName"]; diff --git a/src/Jackett/Indexers/SceneAccess.cs b/src/Jackett/Indexers/SceneAccess.cs index 4f0ecdb63..d29372658 100644 --- a/src/Jackett/Indexers/SceneAccess.cs +++ b/src/Jackett/Indexers/SceneAccess.cs @@ -80,14 +80,14 @@ namespace Jackett.Indexers var content = new FormUrlEncodedContent(pairs); string responseContent; - JArray cookieJArray; + var configSaveData = new JObject(); if (Program.IsWindows) { // If Windows use .net http var response = await client.PostAsync(LoginUrl, content); responseContent = await response.Content.ReadAsStringAsync(); - cookieJArray = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); } else { @@ -95,7 +95,7 @@ namespace Jackett.Indexers var response = await CurlHelper.PostAsync(LoginUrl, pairs); responseContent = Encoding.UTF8.GetString(response.Content); cookieHeader = response.CookieHeader; - cookieJArray = new JArray(response.CookiesFlat); + configSaveData["cookie_header"] = cookieHeader; } if (!responseContent.Contains("nav_profile")) @@ -107,9 +107,6 @@ namespace Jackett.Indexers } else { - var configSaveData = new JObject(); - configSaveData["cookies"] = cookieJArray; - if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -119,7 +116,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } @@ -166,7 +163,7 @@ namespace Jackett.Indexers var sizeStr = qRow.Find(".ttr_size").Contents()[0].NodeValue; var sizeParts = sizeStr.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeParts[1], float.Parse(sizeParts[0], NumberStyles.Float | NumberStyles.AllowThousands)); + release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); var timeStr = qRow.Find(".ttr_added").Text(); DateTime time; @@ -175,8 +172,8 @@ namespace Jackett.Indexers release.PublishDate = time; } - release.Seeders = int.Parse(qRow.Find(".ttr_seeders").Text(), NumberStyles.AllowThousands); - release.Peers = int.Parse(qRow.Find(".ttr_leechers").Text(), NumberStyles.AllowThousands) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".ttr_seeders").Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".ttr_leechers").Text()) + release.Seeders; releases.Add(release); } diff --git a/src/Jackett/Indexers/ShowRSS.cs b/src/Jackett/Indexers/ShowRSS.cs index 50518f893..4d26bfe79 100644 --- a/src/Jackett/Indexers/ShowRSS.cs +++ b/src/Jackett/Indexers/ShowRSS.cs @@ -135,7 +135,6 @@ namespace Jackett.Indexers } ReleaseInfo release; - TorrentzHelper td; string serie_title; foreach (XmlNode node in xmlDoc.GetElementsByTagName("item")) diff --git a/src/Jackett/Indexers/Strike.cs b/src/Jackett/Indexers/Strike.cs index abb62a942..b30eac578 100644 --- a/src/Jackett/Indexers/Strike.cs +++ b/src/Jackett/Indexers/Strike.cs @@ -36,7 +36,10 @@ namespace Jackett.Indexers const string DefaultUrl = "https://getstrike.net"; - const string DownloadUrl = "/api/v2/torrents/download/?hash={0}"; + + //const string DownloadUrl = "/api/v2/torrents/download/?hash={0}"; + const string DownloadUrl = "/torrents/api/download/{0}.torrent"; + const string SearchUrl = "/api/v2/torrents/search/?category=TV&phrase={0}"; string BaseUrl; @@ -125,7 +128,7 @@ namespace Jackett.Indexers release.InfoHash = (string)result["torrent_hash"]; release.MagnetUri = new Uri((string)result["magnet_uri"]); - release.Link = new Uri(string.Format("{0}{1}{2}", baseUrl, DownloadUrl, release.InfoHash)); + release.Link = new Uri(string.Format("{0}{1}", baseUrl, string.Format(DownloadUrl, release.InfoHash))); releases.Add(release); } diff --git a/src/Jackett/Indexers/ThePirateBay.cs b/src/Jackett/Indexers/ThePirateBay.cs index 715aef264..8cf872a5f 100644 --- a/src/Jackett/Indexers/ThePirateBay.cs +++ b/src/Jackett/Indexers/ThePirateBay.cs @@ -28,10 +28,9 @@ namespace Jackett.Indexers public bool IsConfigured { get; private set; } - const string DefaultUrl = "https://thepiratebay.gd"; - const string SearchUrl = "/s/?q=\"{0}\"&category=205&page=0&orderby=99"; - const string SearchUrl2 = "/s/?q=\"{0}\"&category=208&page=0&orderby=99"; - const string SwitchSingleViewUrl = "/switchview.php?view=s"; + const string DefaultUrl = "https://thepiratebay.mn"; + const string SearchUrl = "/search/{0}/0/99/208"; + const string SearchUrl2 = "/search/{0}/0/99/205"; string BaseUrl; @@ -41,6 +40,7 @@ namespace Jackett.Indexers public ThePirateBay() { + BaseUrl = DefaultUrl; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -54,7 +54,7 @@ namespace Jackett.Indexers public Task GetConfigurationForSetup() { - var config = new ConfigurationDataUrl(DefaultUrl); + var config = new ConfigurationDataUrl(BaseUrl); return Task.FromResult(config); } @@ -108,25 +108,19 @@ namespace Jackett.Indexers foreach (var episodeSearchUrl in searchUrls) { - var message = new HttpRequestMessage - { - Method = HttpMethod.Get, - RequestUri = new Uri(baseUrl + SwitchSingleViewUrl) - }; - message.Headers.Referrer = new Uri(episodeSearchUrl); string results; if (Program.IsWindows) { - var response = await client.SendAsync(message); - results = await response.Content.ReadAsStringAsync(); + results = await client.GetStringAsync(episodeSearchUrl); } else { - var response = await CurlHelper.GetAsync(baseUrl + SwitchSingleViewUrl, null, episodeSearchUrl); + var response = await CurlHelper.GetAsync(episodeSearchUrl, null, episodeSearchUrl); results = Encoding.UTF8.GetString(response.Content); } + try { CQ dom = results; @@ -136,7 +130,8 @@ namespace Jackett.Indexers { var release = new ReleaseInfo(); - CQ qLink = row.ChildElements.ElementAt(1).Cq().Children("a").First(); + CQ qRow = row.Cq(); + CQ qLink = qRow.Find(".detName > .detLink").First(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; @@ -145,13 +140,27 @@ namespace Jackett.Indexers release.Comments = new Uri(baseUrl + "/" + qLink.Attr("href").TrimStart('/')); release.Guid = release.Comments; - var timeString = row.ChildElements.ElementAt(2).Cq().Text(); + var downloadCol = row.ChildElements.ElementAt(1).Cq().Children("a"); + release.MagnetUri = new Uri(downloadCol.Attr("href")); + release.InfoHash = release.MagnetUri.ToString().Split(':')[3].Split('&')[0]; + + var descString = qRow.Find(".detDesc").Text().Trim(); + var descParts = descString.Split(','); + + var timeString = descParts[0].Split(' ')[1]; + if (timeString.Contains("mins ago")) - release.PublishDate = (DateTime.Now - TimeSpan.FromMinutes(int.Parse(timeString.Split(' ')[0]))); + { + release.PublishDate = (DateTime.Now - TimeSpan.FromMinutes(ParseUtil.CoerceInt(timeString.Split(' ')[0]))); + } else if (timeString.Contains("Today")) + { release.PublishDate = (DateTime.UtcNow - TimeSpan.FromHours(2) - TimeSpan.Parse(timeString.Split(' ')[1])).ToLocalTime(); + } else if (timeString.Contains("Y-day")) + { release.PublishDate = (DateTime.UtcNow - TimeSpan.FromHours(26) - TimeSpan.Parse(timeString.Split(' ')[1])).ToLocalTime(); + } else if (timeString.Contains(':')) { var utc = DateTime.ParseExact(timeString, "MM-dd HH:mm", CultureInfo.InvariantCulture) - TimeSpan.FromHours(2); @@ -163,17 +172,13 @@ namespace Jackett.Indexers release.PublishDate = DateTime.SpecifyKind(utc, DateTimeKind.Utc).ToLocalTime(); } - var downloadCol = row.ChildElements.ElementAt(3).Cq().Find("a"); - release.MagnetUri = new Uri(downloadCol.Attr("href")); - release.InfoHash = release.MagnetUri.ToString().Split(':')[3].Split('&')[0]; - - var sizeString = row.ChildElements.ElementAt(4).Cq().Text().Split(' '); - var sizeVal = float.Parse(sizeString[0], CultureInfo.InvariantCulture); - var sizeUnit = sizeString[1]; + var sizeParts = descParts[1].Split(new char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries); + var sizeVal = ParseUtil.CoerceFloat(sizeParts[1]); + var sizeUnit = sizeParts[2]; release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); - release.Seeders = int.Parse(row.ChildElements.ElementAt(5).Cq().Text()); - release.Peers = int.Parse(row.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(2).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(3).Cq().Text()) + release.Seeders; releases.Add(release); } diff --git a/src/Jackett/Indexers/TorrentDay.cs b/src/Jackett/Indexers/TorrentDay.cs index d53d79df9..70c2914fc 100644 --- a/src/Jackett/Indexers/TorrentDay.cs +++ b/src/Jackett/Indexers/TorrentDay.cs @@ -107,7 +107,7 @@ namespace Jackett.Indexers else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -118,7 +118,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -150,11 +150,11 @@ namespace Jackett.Indexers var sizeStr = qRow.Find(".sizeInfo").Text().Trim(); var sizeParts = sizeStr.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeParts[1], float.Parse(sizeParts[0])); + release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); - var dateStr = qRow.Find(".ulInfo").Text().Trim(); + var dateStr = qRow.Find(".ulInfo").Text().Split('|').Last().Trim(); var dateParts = dateStr.Split(' '); - var dateValue = int.Parse(dateParts[1]); + var dateValue = ParseUtil.CoerceInt(dateParts[0]); TimeSpan ts = TimeSpan.Zero; if (dateStr.Contains("sec")) ts = TimeSpan.FromSeconds(dateValue); @@ -172,8 +172,8 @@ namespace Jackett.Indexers ts = TimeSpan.FromDays(dateValue * 365); release.PublishDate = DateTime.Now - ts; - release.Seeders = int.Parse(qRow.Find(".seedersInfo").Text(), NumberStyles.AllowThousands); - release.Peers = int.Parse(qRow.Find(".leechersInfo").Text(), NumberStyles.AllowThousands) + release.Seeders; + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".seedersInfo").Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".leechersInfo").Text()) + release.Seeders; releases.Add(release); } diff --git a/src/Jackett/Indexers/TorrentLeech.cs b/src/Jackett/Indexers/TorrentLeech.cs index 2e8610abf..c865059a3 100644 --- a/src/Jackett/Indexers/TorrentLeech.cs +++ b/src/Jackett/Indexers/TorrentLeech.cs @@ -90,7 +90,7 @@ namespace Jackett.Indexers else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -101,7 +101,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -146,10 +146,10 @@ namespace Jackett.Indexers release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); var sizeStringParts = qRow.Children().ElementAt(4).InnerText.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeStringParts[1], float.Parse(sizeStringParts[0])); + release.Size = ReleaseInfo.GetBytes(sizeStringParts[1], ParseUtil.CoerceFloat(sizeStringParts[0])); - release.Seeders = int.Parse(qRow.Find(".seeders").Text()); - release.Peers = release.Seeders + int.Parse(qRow.Find(".leechers").Text()); + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".seeders").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find(".leechers").Text()); releases.Add(release); } diff --git a/src/Jackett/Indexers/TorrentShack.cs b/src/Jackett/Indexers/TorrentShack.cs index 74366b36a..d7b88c705 100644 --- a/src/Jackett/Indexers/TorrentShack.cs +++ b/src/Jackett/Indexers/TorrentShack.cs @@ -91,7 +91,7 @@ namespace Jackett.Indexers else { var configSaveData = new JObject(); - configSaveData["cookies"] = cookies.ToJson(SiteLink); + cookies.DumpToJson(SiteLink, configSaveData); if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -103,7 +103,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); IsConfigured = true; } @@ -139,9 +139,11 @@ namespace Jackett.Indexers else { var dateParts = dateStr.Split(' '); - var dateValue = int.Parse(dateParts[0]); + var dateValue = ParseUtil.CoerceInt(dateParts[0]); TimeSpan ts = TimeSpan.Zero; - if (dateStr.Contains("sec")) + if (dateStr.Contains("Just now")) + ts = TimeSpan.Zero; + else if (dateStr.Contains("sec")) ts = TimeSpan.FromSeconds(dateValue); else if (dateStr.Contains("min")) ts = TimeSpan.FromMinutes(dateValue); @@ -160,9 +162,9 @@ namespace Jackett.Indexers var sizeStr = qRow.Find(".size")[0].ChildNodes[0].NodeValue.Trim(); var sizeParts = sizeStr.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeParts[1], float.Parse(sizeParts[0], NumberStyles.AllowThousands)); - release.Seeders = int.Parse(qRow.Children().ElementAt(6).InnerText.Trim(), NumberStyles.AllowThousands); - release.Peers = int.Parse(qRow.Children().ElementAt(7).InnerText.Trim(), NumberStyles.AllowThousands) + release.Seeders; + release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); + release.Seeders = ParseUtil.CoerceInt(qRow.Children().ElementAt(6).InnerText.Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Children().ElementAt(7).InnerText.Trim()) + release.Seeders; releases.Add(release); } diff --git a/src/Jackett/Indexers/Torrentz.cs b/src/Jackett/Indexers/Torrentz.cs index 78b60edf1..4fcb136fa 100644 --- a/src/Jackett/Indexers/Torrentz.cs +++ b/src/Jackett/Indexers/Torrentz.cs @@ -232,13 +232,13 @@ namespace Jackett.Indexers switch (counter) { case 0: - this.Size = ReleaseInfo.BytesFromMB(long.Parse(val.Substring(0, val.IndexOf(" ") - 1))); + this.Size = ReleaseInfo.BytesFromMB(ParseUtil.CoerceLong(val.Substring(0, val.IndexOf(" ") - 1))); break; case 1: - this.Seeders = int.Parse(val.Contains(",") ? val.Remove(val.IndexOf(","), 1) : val); + this.Seeders = ParseUtil.CoerceInt(val.Contains(",") ? val.Remove(val.IndexOf(","), 1) : val); break; case 2: - this.Peers = int.Parse(val.Contains(",") ? val.Remove(val.IndexOf(","), 1) : val); + this.Peers = ParseUtil.CoerceInt(val.Contains(",") ? val.Remove(val.IndexOf(","), 1) : val); break; case 3: this.hash = val; diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index b70d9a276..d7c11ccae 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -12,7 +12,6 @@ v4.5.1 512 - false publish\ true Disk @@ -25,6 +24,7 @@ true 0 1.0.0.%2a + false false true @@ -57,11 +57,9 @@ ..\packages\CsQuery.1.3.4\lib\net40\CsQuery.dll - - ..\packages\modernhttpclient.2.3.0\lib\Portable-Net45+WinRT45+WP8+WPA81\ModernHttpClient.dll - - - ..\packages\NLog.3.2.0.0\lib\net45\NLog.dll + + ..\packages\NLog.Windows.Forms.2.0.0.0\lib\net35\NLog.Windows.Forms.dll + True @@ -76,14 +74,16 @@ - ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NLog.4.0.1\lib\net45\NLog.dll - @@ -116,6 +116,7 @@ Main.cs + @@ -125,7 +126,6 @@ - @@ -160,30 +160,21 @@ PreserveNewest - - PreserveNewest - PreserveNewest + PreserveNewest - - - PreserveNewest - - - Always - - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest @@ -211,10 +202,10 @@ PreserveNewest - Always + PreserveNewest - Always + PreserveNewest PreserveNewest @@ -232,35 +223,35 @@ PreserveNewest - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest PreserveNewest - Always + PreserveNewest @@ -286,6 +277,17 @@ false + + + {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} + 1 + 0 + 0 + tlbimp + False + True + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett/Main.Designer.cs b/src/Jackett/Main.Designer.cs index fff94fc29..d881a2821 100644 --- a/src/Jackett/Main.Designer.cs +++ b/src/Jackett/Main.Designer.cs @@ -1,4 +1,6 @@ -namespace Jackett +#if !__MonoCS__ + +namespace Jackett { partial class Main { @@ -97,4 +99,5 @@ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemShutdown; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/Jackett/Main.cs b/src/Jackett/Main.cs index 7ebbab2ff..250aff2ce 100644 --- a/src/Jackett/Main.cs +++ b/src/Jackett/Main.cs @@ -1,10 +1,12 @@ -using Microsoft.Win32; +#if !__MonoCS__ +using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Linq; using System.Reflection; using System.Text; @@ -57,20 +59,38 @@ namespace Jackett { get { - RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); - if (rkApp.GetValue(ProgramTitle) == null) - return false; - else - return true; + return File.Exists(ShortcutPath); } set { - RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); if (value && !AutoStart) - rkApp.SetValue(ProgramTitle, Application.ExecutablePath.ToString()); + { + CreateShortcut(); + } else if (!value && AutoStart) - rkApp.DeleteValue(ProgramTitle, false); + { + File.Delete(ShortcutPath); + } } } + + public string ShortcutPath + { + get + { + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Jackett.lnk"); + } + } + + private void CreateShortcut() + { + var appPath = Assembly.GetExecutingAssembly().Location; + var shell = new IWshRuntimeLibrary.WshShell(); + var shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(ShortcutPath); + shortcut.Description = Assembly.GetExecutingAssembly().GetName().Name; + shortcut.TargetPath = appPath; + shortcut.Save(); + } } } +#endif \ No newline at end of file diff --git a/src/Jackett/ParseUtil.cs b/src/Jackett/ParseUtil.cs new file mode 100644 index 000000000..7eb7b8fcf --- /dev/null +++ b/src/Jackett/ParseUtil.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett +{ + public static class ParseUtil + { + public static float CoerceFloat(string str) + { + return float.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static int CoerceInt(string str) + { + return int.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static long CoerceLong(string str) + { + return long.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture); + } + + } +} diff --git a/src/Jackett/Program.cs b/src/Jackett/Program.cs index c6a8b93cc..cc16b2bc1 100644 --- a/src/Jackett/Program.cs +++ b/src/Jackett/Program.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json.Linq; using NLog; using NLog.Config; using NLog.Targets; +using NLog.Windows.Forms; using System; using System.Collections.Generic; using System.Diagnostics; @@ -18,7 +19,7 @@ namespace Jackett { class Program { - public static string AppConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); + public static string AppConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Jackett"); public static Server ServerInstance { get; private set; } @@ -36,6 +37,8 @@ namespace Jackett { ExitEvent = new ManualResetEvent(false); + MigrateSettingsDirectory(); + try { if (!Directory.Exists(AppConfigDirectory)) @@ -68,12 +71,14 @@ namespace Jackett if (Program.IsWindows) { +#if !__MonoCS__ var logAlert = new MessageBoxTarget(); logConfig.AddTarget("alert", logAlert); logAlert.Layout = "${message}"; logAlert.Caption = "Alert"; var logAlertRule = new LoggingRule("*", LogLevel.Fatal, logAlert); logConfig.LoggingRules.Add(logAlertRule); +#endif } var logConsole = new ConsoleTarget(); @@ -93,12 +98,14 @@ namespace Jackett await ServerInstance.Start(); }); - - try { if (Program.IsWindows) + { +#if !__MonoCS__ Application.Run(new Main()); +#endif + } } catch (Exception) { @@ -113,17 +120,20 @@ namespace Jackett Console.WriteLine("Server thread exit"); } - public static void RestartServer() + static void MigrateSettingsDirectory() { - - ServerInstance.Stop(); - ServerInstance = null; - var serverTask = Task.Run(async () => + try { - ServerInstance = new Server(); - await ServerInstance.Start(); - }); - Task.WaitAll(serverTask); + string oldDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); + if (Directory.Exists(oldDir) && !Directory.Exists(AppConfigDirectory)) + { + Directory.Move(oldDir, AppConfigDirectory); + } + } + catch (Exception ex) + { + Console.WriteLine("ERROR could not migrate settings directory " + ex); + } } static void ReadSettingsFile() diff --git a/src/Jackett/Properties/AssemblyInfo.cs b/src/Jackett/Properties/AssemblyInfo.cs index 4c36cbcf8..4cd32421c 100644 --- a/src/Jackett/Properties/AssemblyInfo.cs +++ b/src/Jackett/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.4.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Jackett/Server.cs b/src/Jackett/Server.cs index 9584a47bc..3931b8137 100644 --- a/src/Jackett/Server.cs +++ b/src/Jackett/Server.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Net; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using System.Windows.Forms; @@ -20,11 +19,6 @@ namespace Jackett public static int Port = DefaultPort; public static bool ListenPublic = true; - private static bool isAuthenticated = false; - private static bool isAuthEnabled = false; - private static string Username = ""; - private static string Password = ""; - HttpListener listener; IndexerManager indexerManager; WebApi webApi; @@ -36,7 +30,6 @@ namespace Jackett // Allow all SSL.. sucks I know but mono on linux is having problems without it.. ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; - ReadServerSettingsFile(); LoadApiKey(); indexerManager = new IndexerManager(); @@ -74,12 +67,7 @@ namespace Jackett listener.Prefixes.Add(string.Format("http://127.0.0.1:{0}/", Port)); } - if (isAuthEnabled && HttpListener.IsSupported) - listener.AuthenticationSchemes = AuthenticationSchemes.Basic; - listener.Start(); - - webApi.server = this; } catch (HttpListenerException ex) { @@ -121,13 +109,6 @@ namespace Jackett error = null; var context = await listener.GetContextAsync(); ProcessHttpRequest(context); - - if (isAuthEnabled && !isAuthenticated && HttpListener.IsSupported) - { - IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener); - result.AsyncWaitHandle.WaitOne(); - } - } catch (ObjectDisposedException ex) { @@ -145,43 +126,6 @@ namespace Jackett } } - - private static void ListenerCallback(IAsyncResult ar) - { - try - { - HttpListener listener = (HttpListener)ar.AsyncState; - HttpListenerContext context = listener.EndGetContext(ar); - HttpListenerBasicIdentity identity = (HttpListenerBasicIdentity)context.User.Identity; - - - if (Security.Base64Encode(identity.Name) != Username || Security.Base64Encode(identity.Password) != Password) - context.Response.StatusCode = 401; - - - if (context.Response.StatusCode != 401) - { - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; - context.Response.Headers["StatusDescription"] = "OK"; - isAuthenticated = true; - } - - try - { - context.Response.Close(); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } - public void Stop() { listener.Stop(); @@ -261,15 +205,6 @@ namespace Jackett else if (!string.IsNullOrEmpty(torznabQuery.SearchTerm)) torznabQuery.ShowTitles = new string[] { torznabQuery.SearchTerm }; - //Replacing non-alphanumeric characters with an empty string - if (torznabQuery.ShowTitles != null) - for (int i = 0; i < torznabQuery.ShowTitles.Length; i++) - { - char[] arr = torznabQuery.ShowTitles[i].ToCharArray(); - arr = Array.FindAll(arr, (c => (char.IsLetterOrDigit(c) || char.IsWhiteSpace(c) || c == '-' || c == '@'))); - torznabQuery.ShowTitles[i] = new string(arr); - } - var releases = await indexer.PerformQuery(torznabQuery); Program.LoggerInstance.Debug(string.Format("Found {0} releases from {1}", releases.Length, indexer.DisplayName)); @@ -310,172 +245,6 @@ namespace Jackett } - private static string ServerConfigFile = Path.Combine(Program.AppConfigDirectory, "config.json"); - - public JObject ReadServerSettingsFile() - { - var path = ServerConfigFile; - JObject jsonReply = new JObject(); - if (File.Exists(path)) - { - jsonReply = JObject.Parse(File.ReadAllText(path)); - Port = (int)jsonReply["port"]; - ListenPublic = (bool)jsonReply["public"]; - Username = (string)jsonReply["Username"]; - Password = (string)jsonReply["Password"]; - isAuthEnabled = (!String.IsNullOrEmpty(Username) && !String.IsNullOrEmpty(Password)); - } - else - { - jsonReply["port"] = Port; - jsonReply["public"] = ListenPublic; - jsonReply["Username"] = Username; - jsonReply["Password"] = Password; - } - return jsonReply; - } - - public Task ApplyPortConfiguration(JToken json) - { - JObject jsonObject = (JObject)json; - JToken jJackettPort = jsonObject.GetValue("port"); - int jackettPort; - if (!IsPort(jJackettPort.ToString())) - throw new CustomException("The value entered is not a valid port"); - else - jackettPort = int.Parse(jJackettPort.ToString()); - - if (jackettPort == Port) - throw new CustomException("The current port is the same as the one being used now."); - else if (ChromeUnsafePorts.RestrictedPorts.Contains(jackettPort)) - throw new CustomException("This port is not allowed due to it not being safe."); - SaveSettings(jackettPort); - - return Task.FromResult(jackettPort); - } - - - public async Task ApplyAuthConfiguration(JToken json) - { - JObject jsonObject = (JObject)json; - JToken jUsername = jsonObject.GetValue("username"); - JToken jPassword = jsonObject.GetValue("password"); - - if (String.IsNullOrWhiteSpace(jUsername.ToString())) - throw new CustomException("Your username can not be empty."); - else if (String.IsNullOrWhiteSpace(jPassword.ToString())) - throw new CustomException("Your password can not be empty."); - else - { - Username = Security.Base64Encode(jUsername.ToString()); - Password = Security.Base64Encode(jPassword.ToString()); - - isAuthEnabled = true; - isAuthenticated = false; - SaveAuthSettings(); - listener.AuthenticationSchemes = AuthenticationSchemes.Basic; - } - - } - - async Task ReadPostDataJson(Stream stream) - { - string postData = await new StreamReader(stream).ReadToEndAsync(); - return JObject.Parse(postData); - } - - private void SaveAuthSettings() - { - JObject json = new JObject(); - json["port"] = Port; - json["public"] = ListenPublic; - json["Password"] = Password; - json["Username"] = Username; - File.WriteAllText(ServerConfigFile, json.ToString()); - } - - private void SaveSettings(int jacketPort) - { - JObject json = new JObject(); - json["port"] = jacketPort; - json["public"] = ListenPublic; - json["Password"] = Password; - json["Username"] = Username; - File.WriteAllText(ServerConfigFile, json.ToString()); - } - - public static bool IsPort(string value) - { - if (string.IsNullOrEmpty(value)) - return false; - - Regex numeric = new Regex(@"^[0-9]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - if (numeric.IsMatch(value)) - { - try - { - if (Convert.ToInt32(value) < 65536) - return true; - } - catch (OverflowException) - { - } - } - - return false; - } - - - public ConfigurationAuthentication GetConfiguration() - { - var config = new ConfigurationAuthentication(); - config.Username.Value = Security.Base64Decode(Username); - config.Password.Value = Security.Base64Decode(Password); - - return config; - } - - public async Task ApplyConfiguration(JToken configJson) - { - var config = new ConfigurationAuthentication(); - config.LoadValuesFromJson(configJson); - Username = config.Username.Value; - Password = config.Password.Value; - isAuthEnabled = true; - SaveAuthSettings(); - - } - - public async Task RemoveAuthConfig() - { - Username = ""; - Password = ""; - isAuthEnabled = false; - isAuthenticated = false; - SaveAuthSettings(); - } - - - public class ConfigurationAuthentication : ConfigurationData - { - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - - DisplayItem ApiInfo; - - public ConfigurationAuthentication() - { - Username = new StringItem { Name = "Username", Value = Server.Username }; - Password = new StringItem { Name = "Password", Value = Server.Password }; - } - - public override Item[] GetItems() - { - return new Item[] { Username, Password }; - } - - } } diff --git a/src/Jackett/SonarApi.cs b/src/Jackett/SonarApi.cs index c5274caaa..cf7178c91 100644 --- a/src/Jackett/SonarApi.cs +++ b/src/Jackett/SonarApi.cs @@ -86,7 +86,15 @@ namespace Jackett string SanitizeTitle(string title) { - return title.Replace("(", "").Replace(")", ""); + char[] arr = title.ToCharArray(); + + arr = Array.FindAll(arr, c => (char.IsLetterOrDigit(c) + || char.IsWhiteSpace(c) + || c == '-' + || c == '.' + )); + title = new string(arr); + return title; } void LoadSettings() @@ -129,9 +137,9 @@ namespace Jackett { var config = new ConfigurationSonarr(); config.LoadValuesFromJson(configJson); - await ReloadNameMappings(config.Host.Value, int.Parse(config.Port.Value), config.ApiKey.Value); + await ReloadNameMappings(config.Host.Value, ParseUtil.CoerceInt(config.Port.Value), config.ApiKey.Value); Host = "http://" + new Uri(config.Host.Value).Host; - Port = int.Parse(config.Port.Value); + Port = ParseUtil.CoerceInt(config.Port.Value); ApiKey = config.ApiKey.Value; SaveSettings(); } diff --git a/src/Jackett/TorznabQuery.cs b/src/Jackett/TorznabQuery.cs index e2f2a20f9..06a5651d9 100644 --- a/src/Jackett/TorznabQuery.cs +++ b/src/Jackett/TorznabQuery.cs @@ -34,7 +34,7 @@ namespace Jackett else if (string.IsNullOrEmpty(Episode)) episodeString = string.Format("S{0:00}", Season); else - episodeString = string.Format("S{0:00}E{1:00}", Season, int.Parse(Episode)); + episodeString = string.Format("S{0:00}E{1:00}", Season, ParseUtil.CoerceInt(Episode)); return episodeString; } @@ -53,16 +53,16 @@ namespace Jackett if (query["extended"] != null) { - q.Extended = int.Parse(query["extended"]); + q.Extended = ParseUtil.CoerceInt(query["extended"]); } q.ApiKey = query["apikey"]; if (query["limit"] != null) { - q.Limit = int.Parse(query["limit"]); + q.Limit = ParseUtil.CoerceInt(query["limit"]); } if (query["offset"] != null) { - q.Offset = int.Parse(query["offset"]); + q.Offset = ParseUtil.CoerceInt(query["offset"]); } int temp; diff --git a/src/Jackett/WebApi.cs b/src/Jackett/WebApi.cs index ca1d4c6a1..8c46f3d6c 100644 --- a/src/Jackett/WebApi.cs +++ b/src/Jackett/WebApi.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; +using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; @@ -15,8 +16,6 @@ namespace Jackett { static string WebContentFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebContent"); static string[] StaticFiles = Directory.EnumerateFiles(WebContentFolder, "*", SearchOption.AllDirectories).ToArray(); - public Server server; - public enum WebApiMethod { @@ -27,13 +26,7 @@ namespace Jackett DeleteIndexer, GetSonarrConfig, ApplySonarrConfig, - TestSonarr, - GetJackettConfig, - ApplyJackettConfig, - JackettRestart, - ApplyAuthenticationConfig, - GetAuthenticationConfig, - RemoveAuthenticationConfig, + TestSonarr } static Dictionary WebApiMethods = new Dictionary { @@ -43,14 +36,8 @@ namespace Jackett { "test_indexer", WebApiMethod.TestIndexer }, { "delete_indexer", WebApiMethod.DeleteIndexer }, { "get_sonarr_config", WebApiMethod.GetSonarrConfig }, - { "get_jackett_config",WebApiMethod.GetJackettConfig}, - { "apply_jackett_config",WebApiMethod.ApplyJackettConfig}, { "apply_sonarr_config", WebApiMethod.ApplySonarrConfig }, - { "jackett_restart", WebApiMethod.JackettRestart }, - { "test_sonarr", WebApiMethod.TestSonarr }, - { "apply_authentication_config", WebApiMethod.ApplyAuthenticationConfig}, - { "get_authentication_config", WebApiMethod.GetAuthenticationConfig}, - {"remove_authentication_config", WebApiMethod.RemoveAuthenticationConfig}, + { "test_sonarr", WebApiMethod.TestSonarr } }; IndexerManager indexerManager; @@ -137,27 +124,9 @@ namespace Jackett case WebApiMethod.ApplySonarrConfig: handlerTask = HandleApplySonarrConfig; break; - case WebApiMethod.ApplyJackettConfig: - handlerTask = HandleApplyJackettConfig; - break; case WebApiMethod.TestSonarr: handlerTask = HandleTestSonarr; break; - case WebApiMethod.GetJackettConfig: - handlerTask = HandleJackettConfig; - break; - case WebApiMethod.JackettRestart: - handlerTask = HandleJackettRestart; - break; - case WebApiMethod.ApplyAuthenticationConfig: - handlerTask = HandleApplyAuthenticationConfig; - break; - case WebApiMethod.GetAuthenticationConfig: - handlerTask = HandleGetAuthenticationConfig; - break; - case WebApiMethod.RemoveAuthenticationConfig: - handlerTask = HandlerRemoveAuthenticationConfig; - break; default: handlerTask = HandleInvalidApiMethod; break; @@ -166,23 +135,6 @@ namespace Jackett await ReplyWithJson(context, jsonReply, method.ToString()); } - async Task HandlerRemoveAuthenticationConfig(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - await server.RemoveAuthConfig(); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - async Task ReplyWithJson(HttpListenerContext context, JToken json, string apiCall) { try @@ -212,45 +164,6 @@ namespace Jackett return jsonReply; } - async Task HandleJackettRestart(HttpListenerContext context) - { - Program.RestartServer(); - return null; - } - - async Task HandleApplyAuthenticationConfig(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - await server.ApplyAuthConfiguration(postData); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - Task HandleGetAuthenticationConfig(HttpListenerContext context) - { - JObject jsonReply = new JObject(); - try - { - jsonReply["config"] = server.GetConfiguration().ToJson(); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Task.FromResult(jsonReply); - } - async Task HandleApplySonarrConfig(HttpListenerContext context) { JToken jsonReply = new JObject(); @@ -268,47 +181,6 @@ namespace Jackett return jsonReply; } - async Task HandleApplyJackettConfig(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - int port = await server.ApplyPortConfiguration(postData); - jsonReply["result"] = "success"; - jsonReply["port"] = port; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - Task HandleJackettConfig(HttpListenerContext context) - { - JObject jsonReply = new JObject(); - try - { - jsonReply["config"] = server.ReadServerSettingsFile(); - jsonReply["result"] = "success"; - } - catch (CustomException ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Task.FromResult(jsonReply); - } - - Task HandleGetSonarrConfig(HttpListenerContext context) { JObject jsonReply = new JObject(); @@ -386,7 +258,7 @@ namespace Jackett { jsonReply["result"] = "success"; jsonReply["api_key"] = ApiKey.CurrentKey; - jsonReply["jackett_port"] = Server.Port; + jsonReply["app_version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString(); JArray items = new JArray(); foreach (var i in indexerManager.Indexers) { diff --git a/src/Jackett/WebContent/custom.css b/src/Jackett/WebContent/custom.css index 601637aef..ee80f8369 100644 --- a/src/Jackett/WebContent/custom.css +++ b/src/Jackett/WebContent/custom.css @@ -1,194 +1,190 @@ - body { - background-image: url("binding_dark.png"); - background-repeat: repeat; - } - - #page { - border-radius: 6px; - background-color: white; - max-width: 900px; - margin: 0 auto; - margin-top: 30px; - padding: 20px; - margin-bottom: 100px; - } - - .container-fluid { - } - - #templates { - display: none; - } - - .card { - background-color: #f9f9f9; - border-radius: 6px; - box-shadow: 1px 1px 5px 2px #cdcdcd; - padding: 10px; - width: 260px; - display: inline-block; - vertical-align: top; - margin: 10px; - } - - .unconfigured-indexer { - height: 170px; - } - - .indexer { - height: 230px; - } - - .add-indexer { - border: 0; - } - - .indexer-logo { - text-align: center; - } - - .indexer-logo > img { - border: 1px solid #828282; - } - - .indexer-name > h3 { - margin-top: 13px; - text-align: center; - } - - .indexer-buttons { - text-align: center; - } - - .indexer-buttons > .btn { - margin-bottom: 10px; - } - - - .indexer-button-test { - width: 60px; - } - - .indexer-add-content { - color: gray; - text-align: center; - } - - .indexer-add-content > .glyphicon { - font-size: 50px; - vertical-align: bottom; - } - - .indexer-add-content > .light-text { - margin-top: 11px; - font-size: 18px; - margin-left: -5px; - } - - - .indexer-host > input { - font-size: 12px; - padding: 2px; - } - - .setup-item-inputstring { - max-width: 260px; - } - - .setup-item-inputbool input { - max-width: 100px; - height: 20px; - } - - .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 { - } - - .input-area > * { - vertical-align: middle; - } - - .input-area > p { - margin-top: 10px; - } - - .input-header { - font-size: 18px; - width: 140px; - 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; - } - - -.floatleft { -float:left +body { + background-image: url("binding_dark.png"); + background-repeat: repeat; } -#authentication-status { - display: inline-block; - width: 300px; - margin-left: 4px; +#page { + border-radius: 6px; + background-color: white; + max-width: 900px; + margin: 0 auto; + margin-top: 30px; + padding: 20px; + margin-bottom: 100px; +} + +.container-fluid { +} + +#templates { + display: none; +} + +.card { + background-color: #f9f9f9; + border-radius: 6px; + box-shadow: 1px 1px 5px 2px #cdcdcd; + padding: 10px; + width: 260px; + display: inline-block; + vertical-align: top; + margin: 10px; +} + +.unconfigured-indexer { + height: 170px; +} + +.indexer { + height: 230px; +} + +.add-indexer { + border: 0; +} + +.indexer-logo { + text-align: center; +} + + .indexer-logo > img { + border: 1px solid #828282; + } + +.indexer-name > h3 { + margin-top: 13px; + text-align: center; +} + +.indexer-buttons { + text-align: center; +} + + .indexer-buttons > .btn { + margin-bottom: 10px; + } + + +.indexer-button-test { + width: 60px; +} + +.indexer-add-content { + color: gray; + text-align: center; +} + + .indexer-add-content > .glyphicon { + font-size: 50px; + vertical-align: bottom; + } + + .indexer-add-content > .light-text { + margin-top: 11px; + font-size: 18px; + margin-left: -5px; + } + + +.indexer-host > input { + font-size: 12px; + padding: 2px; +} + +.setup-item-inputstring { + max-width: 260px; +} + +.setup-item-inputbool input { + max-width: 100px; + height: 20px; +} + +.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 { +} + + .input-area > * { + vertical-align: middle; + } + + .input-area > p { + margin-top: 10px; + } + +.input-header { + font-size: 18px; + width: 140px; + 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: 0 auto; + margin-top: 10px; + text-align: center; } diff --git a/src/Jackett/WebContent/custom.js b/src/Jackett/WebContent/custom.js index 68fe76299..38c4871de 100644 --- a/src/Jackett/WebContent/custom.js +++ b/src/Jackett/WebContent/custom.js @@ -1,8 +1,6 @@  reloadIndexers(); -loadJackettSettings(); -loadAuthenticationStatus(); loadSonarrInfo(); function loadSonarrInfo() { @@ -26,429 +24,6 @@ function loadSonarrInfo() { }); } -function loadJackettSettings() { - getJackettConfig(function (data) { - console.log(data); - $("#jackett-port").val(data.config.port); - }); -} - -function getJackettConfig(callback) { - var jqxhr = $.get("get_jackett_config", function (data) { - - callback(data); - console.log(data); - }).fail(function () { - doNotify("Error loading Jackett settings, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); -} - -function loadAuthenticationStatus() -{ - getAuthenticationConfig(function (data) { - var config = data.config; - if (config[0].value && config[1].value) - $("#authentication-status").text("Enabled"); - else - $("#authentication-status").text("Disabled"); - }); -} - -function getSonarrConfig(callback) { - var jqxhr = $.get("get_sonarr_config", function (data) { - callback(data); - }).fail(function () { - doNotify("Error loading Sonarr API configuration, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); -} - - -$("#sonarr-settings").click(function () { - getSonarrConfig(function (data) { - var config = data.config; - - var configForm = newConfigModal("Sonarr API", config); - - var $goButton = configForm.find(".setup-indexer-go"); - $goButton.click(function () { - var data = getConfigModalJson(configForm); - - var originalBtnText = $goButton.html(); - $goButton.prop('disabled', true); - $goButton.html($('#templates > .spinner')[0].outerHTML); - - var jqxhr = $.post("apply_sonarr_config", JSON.stringify(data), function (data) { - if (data.result == "error") { - if (data.config) { - populateSetupForm(data.indexer, data.name, data.config); - } - doNotify("Configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - configForm.modal("hide"); - loadSonarrInfo(); - doNotify("Successfully configured Sonarr API", "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }).always(function () { - $goButton.html(originalBtnText); - $goButton.prop('disabled', false); - }); - }); - - configForm.modal("show"); - - }); -}); - -//$("#Authenticate-jackett").click(function () { -// getAuthenticationConfig(function (data) { -// var config = data.config; -// var configForm = newAuthenticationModal("Authenication", config); - -// var $removeButton = configForm.find(".remove-auth"); -// $removeButton.click(function () { -// var originalBtnText = $goButton.html(); -// var jqxhr = $.post("remove_authentication_config", JSON.stringify(data), function (data) { -// if (data.result == "error") -// doNotify("Authentication configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); -// else { -// loadAuthenticationStatus(); -// configForm.modal("hide"); -// doNotify("Successfully removed authentication", "success", "glyphicon glyphicon-ok"); -// } - -// }).fail(function () { -// doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); -// }).always(function () { -// $removeButton.html(originalBtnText); -// $removeButton.prop('disabled', false); -// }); - - -// }); - -// var $goButton = configForm.find(".setup-indexer-go"); -// $goButton.click(function () { -// var data = getConfigModalJson(configForm); -// var originalBtnText = $goButton.html(); -// $goButton.prop('disabled', true); -// $goButton.html($('#templates > .spinner')[0].outerHTML); - -// var jqxhr = $.post("apply_authentication_config", JSON.stringify(data), function (data) { - -// if (data.result == "error") { -// if (data.config) { -// populateSetupForm(data.indexer, data.name, data.config); -// } -// doNotify("Authentication configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); -// } -// else { -// loadAuthenticationStatus(); -// restartJackett(); -// configForm.modal("hide"); -// doNotify("Successfully configured authentication", "success", "glyphicon glyphicon-ok"); -// } - - -// }).fail(function () { -// doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); -// }).always(function () { -// $goButton.html(originalBtnText); -// $goButton.prop('disabled', false); -// }); - - -// }); - -// configForm.modal("show"); - -// }); -//}); - -function restartJackett() { - var jqxhr0 = $.post("jackett_restart", null, function (data_restart) { }); - console.log("restart"); - window.setTimeout(function () { - url = window.location.href; - window.location.href = url; - - }, 3000); -} - - -function getAuthenticationConfig(callback) { - var jqxhr = $.get("get_authentication_config", function (data) { - callback(data); - }).fail(function () { - doNotify("Error loading authentication configuration, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); -} - - -$("#change-jackett-port").click(function () { - var jackett_port = $("#jackett-port").val(); - var jsonObject = JSON.parse('{"port":"'+jackett_port+'"}'); - - var jqxhr = $.post("apply_jackett_config", JSON.stringify(jsonObject), function (data) { - - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } else { - doNotify("The port has been changed. Jackett will now restart...", "success", "glyphicon glyphicon-ok"); - var jqxhr0 = $.post("jackett_restart", null, function (data_restart) { }); - - window.setTimeout(function () { - url = window.location.href; - window.location.href = url.substr(0,url.lastIndexOf(":")+1) + data.port; - - }, 3000); - - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - $("#sonarr-test").click(function () { - var jqxhr = $.get("get_indexers", function (data) { - if (data.result == "error") - doNotify("Test failed for Sonarr API\n" + data.error, "danger", "glyphicon glyphicon-alert"); - else - doNotify("Test successful for Sonarr API", "success", "glyphicon glyphicon-ok"); - }).fail(function () { - doNotify("Error testing Sonarr, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - - - - function reloadIndexers() { - $('#indexers').hide(); - $('#indexers > .indexer').remove(); - $('#unconfigured-indexers').empty(); - var jqxhr = $.get("get_indexers", function (data) { - $("#api-key-input").val(data.api_key); - displayIndexers(data.items); - }).fail(function () { - doNotify("Error loading indexers, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - } - - function displayIndexers(items) { - var indexerTemplate = Handlebars.compile($("#templates > .configured-indexer")[0].outerHTML); - var unconfiguredIndexerTemplate = Handlebars.compile($("#templates > .unconfigured-indexer")[0].outerHTML); - for (var i = 0; i < items.length; i++) { - var item = items[i]; - item.torznab_host = resolveUrl("/api/" + item.id); - if (item.configured) - $('#indexers').append(indexerTemplate(item)); - else - $('#unconfigured-indexers').append($(unconfiguredIndexerTemplate(item))); - } - - var addIndexerButton = $("#templates > .add-indexer")[0].outerHTML; - $('#indexers').append(addIndexerButton); - - $('#indexers').fadeIn(); - prepareSetupButtons(); - prepareTestButtons(); - prepareDeleteButtons(); - } - - function prepareDeleteButtons() { - $(".indexer-button-delete").each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - $btn.click(function () { - var jqxhr = $.post("delete_indexer", JSON.stringify({ indexer: id }), function (data) { - if (data.result == "error") { - doNotify("Delete error for " + id + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - doNotify("Deleted " + id, "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Error deleting indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); - }).always(function () { - reloadIndexers(); - }); - }); - }); - } - - function prepareSetupButtons() { - $('.indexer-setup').each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - $btn.click(function () { - displayIndexerSetup(id); - }); - }); - } - - function prepareTestButtons() { - $(".indexer-button-test").each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - $btn.click(function () { - doNotify("Test started for " + id, "info", "glyphicon glyphicon-transfer"); - var jqxhr = $.post("test_indexer", JSON.stringify({ indexer: id }), function (data) { - if (data.result == "error") { - doNotify("Test failed for " + data.name + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - doNotify("Test successful for " + data.name, "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Error testing indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); - }); - }); - }); - } - - function displayIndexerSetup(id) { - - var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: id }), function (data) { - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } - populateSetupForm(id, data.name, data.config); - - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - - $("#select-indexer-modal").modal("hide"); - } - - function populateConfigItems(configForm, config) { - var $formItemContainer = configForm.find(".config-setup-form"); - $formItemContainer.empty(); - var setupItemTemplate = Handlebars.compile($("#templates > .setup-item")[0].outerHTML); - for (var i = 0; i < config.length; i++) { - var item = config[i]; - var setupValueTemplate = Handlebars.compile($("#templates > .setup-item-" + item.type)[0].outerHTML); - item.value_element = setupValueTemplate(item); - $formItemContainer.append(setupItemTemplate(item)); - } - } - - - function newAuthenticationModal(title, config) - { - //config-authentication-modal - var configTemplate = Handlebars.compile($("#templates > .config-authentication-modal")[0].outerHTML); - var configForm = $(configTemplate({ title: title })); - - $("#modals").append(configForm); - - populateConfigItems(configForm, config); - - return configForm; - } - - function newConfigModal(title, config) { - //config-setup-modal - var configTemplate = Handlebars.compile($("#templates > .config-setup-modal")[0].outerHTML); - var configForm = $(configTemplate({ title: title })); - - $("#modals").append(configForm); - - populateConfigItems(configForm, config); - - return configForm; - //modal.remove(); - } - - function getConfigModalJson(configForm) { - var configJson = {}; - configForm.find(".config-setup-form").children().each(function (i, el) { - $el = $(el); - var type = $el.data("type"); - var id = $el.data("id"); - switch (type) { - case "inputstring": - configJson[id] = $el.find(".setup-item-inputstring").val(); - break; - case "inputbool": - configJson[id] = $el.find(".setup-item-checkbox").val(); - break; - } - }); - return configJson; - } - - function populateSetupForm(indexerId, name, config) { - - var configForm = newConfigModal(name, config); - - var $goButton = configForm.find(".setup-indexer-go"); - $goButton.click(function () { - var data = { indexer: indexerId, name: name }; - data.config = getConfigModalJson(configForm); - - var originalBtnText = $goButton.html(); - $goButton.prop('disabled', true); - $goButton.html($('#templates > .spinner')[0].outerHTML); - - var jqxhr = $.post("configure_indexer", JSON.stringify(data), function (data) { - if (data.result == "error") { - if (data.config) { - populateConfigItems(configForm, data.config); - } - doNotify("Configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - configForm.modal("hide"); - reloadIndexers(); - doNotify("Successfully configured " + data.name, "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }).always(function () { - $goButton.html(originalBtnText); - $goButton.prop('disabled', false); - }); - }); - - configForm.modal("show"); - } - - function resolveUrl(url) { - var a = document.createElement('a'); - a.href = url; - url = a.href; - return url; - } - - - - function doNotify(message, type, icon) { - $.notify({ - message: message, - icon: icon - }, { - element: 'body', - type: type, - allow_dismiss: true, - z_index: 9000, - mouse_over: 'pause', - placement: { - from: "bottom", - align: "center" - } - }); - } - - function clearNotifications() { - $('[data-notify="container"]').remove(); - } - function getSonarrConfig(callback) { var jqxhr = $.get("get_sonarr_config", function (data) { callback(data); @@ -514,6 +89,7 @@ function reloadIndexers() { $('#unconfigured-indexers').empty(); var jqxhr = $.get("get_indexers", function (data) { $("#api-key-input").val(data.api_key); + $("#app-version").html(data.app_version); displayIndexers(data.items); }).fail(function () { doNotify("Error loading indexers, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); diff --git a/src/Jackett/WebContent/index.html b/src/Jackett/WebContent/index.html index 78862ec02..ad6ccb22b 100644 --- a/src/Jackett/WebContent/index.html +++ b/src/Jackett/WebContent/index.html @@ -28,7 +28,7 @@ Sonarr API Host: - -

- Authentication: -
-
@@ -69,6 +56,13 @@ +
+ + + + - -