예제 #1
0
        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));
        }
예제 #2
0
        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")
            });
        }
예제 #3
0
        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);
                }
            }
        }
예제 #4
0
        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));
        }
예제 #5
0
        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)
            });
        }