public IActionResult UpdateConfig([FromBody] Common.Models.DTO.ServerConfig config) { var webHostRestartNeeded = false; var originalPort = serverConfig.Port; var originalAllowExternal = serverConfig.AllowExternal; var port = config.port; var external = config.external; var saveDir = config.blackholedir; var updateDisabled = config.updatedisabled; var preRelease = config.prerelease; var logging = config.logging; var basePathOverride = config.basepathoverride; if (basePathOverride != null) { basePathOverride = basePathOverride.TrimEnd('/'); if (!string.IsNullOrWhiteSpace(basePathOverride) && !basePathOverride.StartsWith("/")) { throw new Exception("The Base Path Override must start with a /"); } } var omdbApiKey = config.omdbkey; var omdbApiUrl = config.omdburl; if (config.basepathoverride != serverConfig.BasePathOverride) { webHostRestartNeeded = true; } serverConfig.UpdateDisabled = updateDisabled; serverConfig.UpdatePrerelease = preRelease; serverConfig.BasePathOverride = basePathOverride; serverConfig.RuntimeSettings.BasePath = serverService.BasePath(); configService.SaveConfig(serverConfig); Helper.SetLogLevel(logging ? LogLevel.Debug : LogLevel.Info); serverConfig.RuntimeSettings.TracingEnabled = logging; if (omdbApiKey != serverConfig.OmdbApiKey || omdbApiUrl != serverConfig.OmdbApiUrl) { serverConfig.OmdbApiKey = omdbApiKey; serverConfig.OmdbApiUrl = omdbApiUrl.TrimEnd('/'); configService.SaveConfig(serverConfig); // HACK indexerService.InitAggregateIndexer(); } if (config.proxy_type != serverConfig.ProxyType || config.proxy_url != serverConfig.ProxyUrl || config.proxy_port != serverConfig.ProxyPort || config.proxy_username != serverConfig.ProxyUsername || config.proxy_password != serverConfig.ProxyPassword) { if (config.proxy_port < 1 || config.proxy_port > 65535) { throw new Exception("The port you have selected is invalid, it must be below 65535."); } serverConfig.ProxyUrl = config.proxy_url; serverConfig.ProxyType = config.proxy_type; serverConfig.ProxyPort = config.proxy_port; serverConfig.ProxyUsername = config.proxy_username; serverConfig.ProxyPassword = config.proxy_password; configService.SaveConfig(serverConfig); webHostRestartNeeded = true; } if (port != serverConfig.Port || external != serverConfig.AllowExternal) { if (ServerUtil.RestrictedPorts.Contains(port)) { throw new Exception("The port you have selected is restricted, try a different one."); } if (port < 1 || port > 65535) { throw new Exception("The port you have selected is invalid, it must be below 65535."); } // Save port to the config so it can be picked up by the if needed when running as admin below. serverConfig.AllowExternal = external; serverConfig.Port = port; configService.SaveConfig(serverConfig); // On Windows change the url reservations if (System.Environment.OSVersion.Platform != PlatformID.Unix) { if (!ServerUtil.IsUserAdministrator()) { try { var consoleExePath = System.Reflection.Assembly.GetExecutingAssembly().CodeBase.Replace(".dll", ".exe"); processService.StartProcessAndLog(consoleExePath, "--ReserveUrls", true); } catch { serverConfig.Port = originalPort; serverConfig.AllowExternal = originalAllowExternal; configService.SaveConfig(serverConfig); throw new Exception("Failed to acquire admin permissions to reserve the new port."); } } else { serverService.ReserveUrls(true); } } webHostRestartNeeded = true; } if (saveDir != serverConfig.BlackholeDir) { if (!string.IsNullOrEmpty(saveDir)) { if (!Directory.Exists(saveDir)) { throw new Exception("Blackhole directory does not exist"); } } serverConfig.BlackholeDir = saveDir; configService.SaveConfig(serverConfig); } if (webHostRestartNeeded) { Thread.Sleep(500); logger.Info("Restarting webhost due to configuration change"); Helper.RestartWebHost(); } serverConfig.ConfigChanged(); return(Json(serverConfig)); }
public async Task <HttpResponseMessage> Call(string indexerID) { var indexer = indexerService.GetIndexer(indexerID); var torznabQuery = TorznabQuery.FromHttpQuery(HttpUtility.ParseQueryString(Request.RequestUri.Query)); if (string.Equals(torznabQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase)) { return(new HttpResponseMessage() { Content = new StringContent(indexer.TorznabCaps.ToXml(), Encoding.UTF8, "application/xml") }); } torznabQuery.ExpandCatsToSubCats(); var allowBadApiDueToDebug = false; #if DEBUG allowBadApiDueToDebug = Debugger.IsAttached; #endif if (!allowBadApiDueToDebug && !string.Equals(torznabQuery.ApiKey, serverService.Config.APIKey, StringComparison.InvariantCultureIgnoreCase)) { logger.Warn(string.Format("A request from {0} was made with an incorrect API key.", Request.GetOwinContext().Request.RemoteIpAddress)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "Incorrect API key")); } if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured.")); } if (torznabQuery.ImdbID != null) { if (torznabQuery.QueryType != "movie") { logger.Warn(string.Format("A non movie request with an imdbid was made from {0}.", Request.GetOwinContext().Request.RemoteIpAddress)); return(GetErrorXML(201, "Incorrect parameter: only movie-search supports the imdbid parameter")); } if (!string.IsNullOrEmpty(torznabQuery.SearchTerm)) { logger.Warn(string.Format("A movie-search request from {0} was made contining q and imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); return(GetErrorXML(201, "Incorrect parameter: please specify either imdbid or q")); } torznabQuery.ImdbID = ParseUtil.GetFullImdbID(torznabQuery.ImdbID); // normalize ImdbID if (torznabQuery.ImdbID == null) { logger.Warn(string.Format("A movie-search request from {0} was made with an invalid imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); return(GetErrorXML(201, "Incorrect parameter: invalid imdbid format")); } if (!indexer.TorznabCaps.SupportsImdbSearch) { logger.Warn(string.Format("A movie-search request with imdbid from {0} was made but the indexer {1} doesn't support it.", Request.GetOwinContext().Request.RemoteIpAddress, indexer.DisplayName)); return(GetErrorXML(203, "Function Not Available: imdbid is not supported by this indexer")); } } var releases = await indexer.PerformQuery(torznabQuery); releases = indexer.CleanLinks(releases); // Some trackers do not keep their clocks up to date and can be ~20 minutes out! foreach (var release in releases.Where(r => r.PublishDate > DateTime.Now)) { release.PublishDate = DateTime.Now; } // Some trackers do not support multiple category filtering so filter the releases that match manually. var filteredReleases = releases = indexer.FilterResults(torznabQuery, releases); int?newItemCount = null; // Cache non query results if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm)) { newItemCount = cacheService.GetNewItemCount(indexer, filteredReleases); cacheService.CacheRssResults(indexer, releases); } // Log info var logBuilder = new StringBuilder(); if (newItemCount != null) { logBuilder.AppendFormat(string.Format("Found {0} ({1} new) releases from {2}", releases.Count(), newItemCount, indexer.DisplayName)); } else { logBuilder.AppendFormat(string.Format("Found {0} releases from {1}", releases.Count(), indexer.DisplayName)); } if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { logBuilder.AppendFormat(" for: {0}", torznabQuery.GetQueryString()); } logger.Info(logBuilder.ToString()); var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); var resultPage = new ResultPage(new ChannelInfo { Title = indexer.DisplayName, Description = indexer.DisplayDescription, Link = new Uri(indexer.SiteLink), ImageUrl = new Uri(serverUrl + "logos/" + indexer.ID + ".png"), ImageTitle = indexer.DisplayName, ImageLink = new Uri(indexer.SiteLink), ImageDescription = indexer.DisplayName }); foreach (var result in releases) { var clone = Mapper.Map <ReleaseInfo>(result); clone.Link = serverService.ConvertToProxyLink(clone.Link, serverUrl, indexerID, "dl", result.Title + ".torrent"); resultPage.Releases.Add(clone); } var xml = resultPage.ToXml(new Uri(serverUrl)); // Force the return as XML return(new HttpResponseMessage() { Content = new StringContent(xml, Encoding.UTF8, "application/rss+xml") }); }
private void ConfigureCacheResults(List <TrackerCacheResult> results) { var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); foreach (var result in results) { var link = result.Link; result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", result.Title + ".torrent"); if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.Server.Config.BlackholeDir)) { result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", string.Empty); } } }
public IActionResult UpdateConfig([FromBody] Common.Models.DTO.ServerConfig config) { var webHostRestartNeeded = false; var originalPort = serverConfig.Port; var originalAllowExternal = serverConfig.AllowExternal; var port = config.port; var external = config.external; var saveDir = config.blackholedir; var updateDisabled = config.updatedisabled; var preRelease = config.prerelease; var enhancedLogging = config.logging; var basePathOverride = config.basepathoverride; if (basePathOverride != null) { basePathOverride = basePathOverride.TrimEnd('/'); if (!string.IsNullOrWhiteSpace(basePathOverride) && !basePathOverride.StartsWith("/")) { throw new Exception("The Base Path Override must start with a /"); } } var baseUrlOverride = config.baseurloverride; if (baseUrlOverride != serverConfig.BaseUrlOverride) { baseUrlOverride = baseUrlOverride.TrimEnd('/'); if (string.IsNullOrWhiteSpace(baseUrlOverride)) { baseUrlOverride = ""; } else if (!Uri.TryCreate(baseUrlOverride, UriKind.Absolute, out var uri) || !(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) { throw new Exception("Base URL Override is invalid. Example: http://jackett:9117"); } serverConfig.BaseUrlOverride = baseUrlOverride; configService.SaveConfig(serverConfig); } var cacheEnabled = config.cache_enabled; var cacheTtl = config.cache_ttl; var cacheMaxResultsPerIndexer = config.cache_max_results_per_indexer; var omdbApiKey = config.omdbkey; var omdbApiUrl = config.omdburl; if (config.basepathoverride != serverConfig.BasePathOverride) { webHostRestartNeeded = true; } serverConfig.UpdateDisabled = updateDisabled; serverConfig.UpdatePrerelease = preRelease; serverConfig.BasePathOverride = basePathOverride; serverConfig.BaseUrlOverride = baseUrlOverride; serverConfig.CacheEnabled = cacheEnabled; serverConfig.CacheTtl = cacheTtl; serverConfig.CacheMaxResultsPerIndexer = cacheMaxResultsPerIndexer; serverConfig.RuntimeSettings.BasePath = serverService.BasePath(); configService.SaveConfig(serverConfig); if (config.flaresolverrurl != serverConfig.FlareSolverrUrl || config.flaresolverr_maxtimeout != serverConfig.FlareSolverrMaxTimeout) { if (string.IsNullOrWhiteSpace(config.flaresolverrurl)) { config.flaresolverrurl = ""; } else if (!Uri.TryCreate(config.flaresolverrurl, UriKind.Absolute, out var uri) || !(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) { throw new Exception("FlareSolverr API URL is invalid. Example: http://127.0.0.1:8191"); } if (config.flaresolverr_maxtimeout < 5000) { throw new Exception("FlareSolverr Max Timeout must be greater than 5000 ms."); } serverConfig.FlareSolverrUrl = config.flaresolverrurl; serverConfig.FlareSolverrMaxTimeout = config.flaresolverr_maxtimeout; configService.SaveConfig(serverConfig); webHostRestartNeeded = true; } if (omdbApiKey != serverConfig.OmdbApiKey || omdbApiUrl != serverConfig.OmdbApiUrl) { serverConfig.OmdbApiKey = omdbApiKey; serverConfig.OmdbApiUrl = omdbApiUrl.TrimEnd('/'); configService.SaveConfig(serverConfig); // HACK indexerService.InitMetaIndexers(); } if (config.proxy_type != serverConfig.ProxyType || config.proxy_url != serverConfig.ProxyUrl || config.proxy_port != serverConfig.ProxyPort || config.proxy_username != serverConfig.ProxyUsername || config.proxy_password != serverConfig.ProxyPassword) { if (config.proxy_port < 1 || config.proxy_port > 65535) { throw new Exception("The port you have selected is invalid, it must be below 65535."); } serverConfig.ProxyType = string.IsNullOrWhiteSpace(config.proxy_url) ? ProxyType.Disabled : config.proxy_type; serverConfig.ProxyUrl = config.proxy_url; serverConfig.ProxyPort = config.proxy_port; serverConfig.ProxyUsername = config.proxy_username; serverConfig.ProxyPassword = config.proxy_password; configService.SaveConfig(serverConfig); webHostRestartNeeded = true; // Remove all results from cache so we can test the new proxy cacheService.CleanCache(); } if (port != serverConfig.Port || external != serverConfig.AllowExternal) { if (ServerUtil.RestrictedPorts.Contains(port)) { throw new Exception("The port you have selected is restricted, try a different one."); } if (port < 1 || port > 65535) { throw new Exception("The port you have selected is invalid, it must be below 65535."); } // Save port to the config so it can be picked up by the if needed when running as admin below. serverConfig.AllowExternal = external; serverConfig.Port = port; configService.SaveConfig(serverConfig); // On Windows change the url reservations if (Environment.OSVersion.Platform != PlatformID.Unix) { if (!ServerUtil.IsUserAdministrator()) { try { var consoleExePath = EnvironmentUtil.JackettExecutablePath().Replace(".dll", ".exe"); processService.StartProcessAndLog(consoleExePath, "--ReserveUrls", true); } catch { serverConfig.Port = originalPort; serverConfig.AllowExternal = originalAllowExternal; configService.SaveConfig(serverConfig); throw new Exception("Failed to acquire admin permissions to reserve the new port."); } } else { serverService.ReserveUrls(); } } webHostRestartNeeded = true; } if (saveDir != serverConfig.BlackholeDir) { if (!string.IsNullOrEmpty(saveDir)) { if (!Directory.Exists(saveDir)) { throw new Exception("Blackhole directory does not exist"); } } serverConfig.BlackholeDir = saveDir; configService.SaveConfig(serverConfig); } if (webHostRestartNeeded) { // we have to restore log level when the server restarts because we are not saving the state in the // configuration. when the server restarts the UI is inconsistent with the active log level // https://github.com/Jackett/Jackett/issues/8315 SetEnhancedLogLevel(false); Thread.Sleep(500); logger.Info("Restarting webhost due to configuration change"); Helper.RestartWebHost(); } else { SetEnhancedLogLevel(enhancedLogging); } serverConfig.ConfigChanged(); return(Json(serverConfig)); }
public async Task <HttpResponseMessage> Call(string indexerID, [FromUri] TorrentPotatoRequest request) { var indexer = indexerService.GetIndexer(indexerID); var allowBadApiDueToDebug = false; #if DEBUG allowBadApiDueToDebug = Debugger.IsAttached; #endif if (!allowBadApiDueToDebug && !string.Equals(request.passkey, serverService.Config.APIKey, StringComparison.InvariantCultureIgnoreCase)) { logger.Warn(string.Format("A request from {0} was made with an incorrect API key.", Request.GetOwinContext().Request.RemoteIpAddress)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "Incorrect API key")); } if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured.")); } if (!indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => MOVIE_CATS.Contains(i))) { logger.Warn(string.Format("Rejected a request to {0} which does not support searching for movies.", indexer.DisplayName)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer does not support movies.")); } var year = 0; if (string.IsNullOrWhiteSpace(request.search)) { // We are searching by IMDB id so look up the name var response = await webClient.GetString(new Utils.Clients.WebRequest("http://www.omdbapi.com/?type=movie&i=" + request.imdbid)); if (response.Status == HttpStatusCode.OK) { JObject result = JObject.Parse(response.Content); if (result["Title"] != null) { request.search = result["Title"].ToString(); year = ParseUtil.CoerceInt(result["Year"].ToString()); } } } var torznabQuery = new TorznabQuery() { ApiKey = request.passkey, Categories = MOVIE_CATS, SearchTerm = request.search, ImdbID = request.imdbid }; IEnumerable <ReleaseInfo> releases = new List <ReleaseInfo>(); if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { releases = await indexer.PerformQuery(torznabQuery); releases = indexer.CleanLinks(releases); } // Cache non query results if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm)) { cacheService.CacheRssResults(indexer, releases); } releases = indexer.FilterResults(torznabQuery, releases); var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); var potatoResponse = new TorrentPotatoResponse(); releases = TorznabUtil.FilterResultsToTitle(releases, torznabQuery.SanitizedSearchTerm, year); releases = TorznabUtil.FilterResultsToImdb(releases, request.imdbid); foreach (var r in releases) { var release = Mapper.Map <ReleaseInfo>(r); release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, indexerID, "dl", release.Title + ".torrent"); // Only accept torrent links, magnet is not supported if (release.Link != null) { potatoResponse.results.Add(new TorrentPotatoResponseItem() { release_name = release.Title + "[" + indexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.> torrent_id = release.Guid.ToString(), details_url = release.Comments.ToString(), download_url = release.Link.ToString(), imdb_id = release.Imdb.HasValue ? "tt" + release.Imdb : null, freeleech = false, type = "movie", size = (long)release.Size / (1024 * 1024), // This is in MB leechers = (int)release.Peers - (int)release.Seeders, seeders = (int)release.Seeders }); } } // Log info if (string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { logger.Info(string.Format("Found {0} torrentpotato releases from {1}", releases.Count(), indexer.DisplayName)); } else { logger.Info(string.Format("Found {0} torrentpotato releases from {1} for: {2}", releases.Count(), indexer.DisplayName, torznabQuery.GetQueryString())); } // Force the return as Json return(new HttpResponseMessage() { Content = new JsonContent(potatoResponse) }); }