Exemple #1
0
        private HttpResult getResults(IEnumerable <NZBResult> results, long total, int offset, APIKey key, FastNZB.ServiceModel.APIRequest req)
        {
            var settings = _settings;
            var response = new Feed()
            {
                Title  = "fastNZB",
                Link   = new Uri(settings.Get <string>("BaseUrl")),
                Total  = total,
                Offset = offset
            };

            var items = new List <Item>();

            foreach (var nzb in results)
            {
                items.Add(new Item()
                {
                    Title       = nzb.Name,
                    Link        = new Uri(nzb.GetLink(settings.Get <string>("BaseUrl"), key.Key, "1")),
                    PublishDate = nzb.Added,
                    Permalink   = settings.Get <string>("BaseUrl") + "/details/" + nzb.Guid,
                    Body        = nzb.Name,
                    Length      = nzb.Size.ToString(),
                    Category    = nzb.CategoryName,
                    CategoryId  = nzb.CategoryId.ToString(),
                    Comments    = new Uri(settings.Get <string>("BaseUrl")),
                    Result      = nzb == null ? new NZBResult() : nzb
                });
            }

            response.Items = items;

            using (var db = ConnectionFactory.OpenDbConnection())
            {
                key.Requests++;
                db.Save <APIKey>(key);

                var request = new FastNZB.ServiceModel.Types.APIRequest {
                    UserId   = key.UserId,
                    APIKeyId = key.Id,
                    Date     = DateTime.Now,
                    results  = total
                }.PopulateWith(req);

                db.Save <FastNZB.ServiceModel.Types.APIRequest>(request);
            }

            return(new HttpResult(response.Serialize(), "text/xml;charset=UTF-8"));
        }
Exemple #2
0
        public object Any(FastNZB.ServiceModel.APIRequest req)
        {
            if (req.o == "json")
            {
                throw new HttpError(500, "JSON Not supported");
            }

            if (req.t != "g" && req.t != "get")
            {
                base.Request.ResponseContentType = MimeTypes.Xml;
            }

            var function = "";
            IEnumerable <NZBResult> results = new List <NZBResult>();
            int total = 0;

            switch (req.t)
            {
            case "caps":
                function = "c";
                break;

            case "g":
            case "get":
                function = "g";
                break;

            case "s":
            case "search":
                function = "s";
                break;

            case "tv":
            case "tvsearch":
                function = "tv";
                break;

            case "m":
            case "movie":
                function = "m";
                break;

            default:
                throw new HttpError(202, "No such function");
            }

            if (function != "c" && !Db.Exists <APIKey>(q => q.Key == req.apikey))
            {
                return(new HttpError(101, "API Key not present or invalid"));
            }

            // api rate limit to 60/minute
            APIKey key = null;

            if (function != "c")
            {
                key = Db.Single <APIKey>(q => q.Key == req.apikey);
                var cacheKey = String.Format("apikey-rate-{0}", key.Id);
                var requests = Cache.Get <int>(cacheKey);
                if (requests == 0 || DateTime.Now > Cache.Get <DateTime>(cacheKey + "-expires"))
                {
                    requests = 1;
                    Cache.Set <int>(cacheKey, requests);
                    Cache.Set <DateTime>(cacheKey + "-expires", DateTime.Now.AddMinutes(1));
                }
                else
                {
                    Cache.Set <int>(cacheKey, requests + 1);
                }

                if (requests > 60)
                {
                    return(new HttpError(500, "Request limit reached, please try again in one minute"));
                }
            }

            // deter scrapers
            if (req.offset > 1000)
            {
                req.offset = 0;
            }

            // TODO, store these caps values somewhere else
            if (function == "c")
            {
                var caps = new Caps()
                {
                    Server = new Server()
                    {
                        Title      = "fastNZB",
                        Email      = "*****@*****.**",
                        Image      = "https://fastnzb.com/assets/img/nzb.png",
                        Appversion = "1.0.0",
                        Version    = "0.1",
                        Strapline  = "A great usenet indexer",
                        Meta       = "usenet,nzbs,cms,community",
                    },
                    Limits = new Limits()
                    {
                        Max     = "100",
                        Default = "100"
                    },
                    Registration = new Registration()
                    {
                        Open      = "yes",
                        Available = "yes"
                    },
                    Searching = new Searching()
                    {
                        Search = new Search()
                        {
                            Available = "yes", SupportedParams = "q"
                        },
                        Tvsearch = new Tvsearch()
                        {
                            Available       = "yes",
                            SupportedParams = "q,vid,tvdbid,traktid,rid,tvmazeid,imdbid,tmdbid,season,ep",
                        },
                        Moviesearch = new Moviesearch()
                        {
                            Available = "yes", SupportedParams = "q,imdbid"
                        },
                        Audiosearch = new Audiosearch()
                        {
                            Available = "no", SupportedParams = ""
                        },
                    },
                    Categories = new Categories()
                    {
                        Category = new List <FastNZB.ServiceModel.Category>()
                        {
                            new FastNZB.ServiceModel.Category()
                            {
                                Id     = "2000",
                                Name   = "Movies",
                                Subcat = new List <Subcat>()
                                {
                                    new Subcat()
                                    {
                                        Id = "2050", Name = "3D"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2060", Name = "BluRay"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2070", Name = "DVD"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2010", Name = "Foreign"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2040", Name = "HD"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2999", Name = "Other"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2030", Name = "SD"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2045", Name = "UHD"
                                    },
                                    new Subcat()
                                    {
                                        Id = "2080", Name = "WEBDL"
                                    },
                                }
                            },
                            new FastNZB.ServiceModel.Category()
                            {
                                Id     = "5000",
                                Name   = "TV",
                                Subcat = new List <Subcat>()
                                {
                                    new Subcat()
                                    {
                                        Id = "5080", Name = "Documentary"
                                    },
                                    new Subcat()
                                    {
                                        Id = "5040", Name = "HD"
                                    },
                                    new Subcat()
                                    {
                                        Id = "5030", Name = "SD"
                                    },
                                    new Subcat()
                                    {
                                        Id = "5010", Name = "WEB-DL"
                                    },
                                }
                            }
                        },
                    }
                };

                var ser = new XmlSerializer(typeof(Caps));
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");

                using (StringWriter textWriter = new Utf8StringWriter()) {
                    ser.Serialize(textWriter, caps, ns);

                    return(new HttpResult(textWriter.ToString(), "text/xml;charset=UTF-8"));
                }
            }
            else if (function == "s") /* ------------------------------------------------------- */
            {
                var catsrch = GetCatSearch(Db, req.cat);

                var whereSql = String.Format(String.Concat(
                                                 "WHERE 1=1 ",
                                                 "{0} {1} {2} {3} "),
                                             !String.IsNullOrEmpty(req.q) ? GetSphinxSearch(req.q) : "",
                                             catsrch,
                                             req.maxage > 0 ? String.Format("AND r.PostDate > NOW() - INTERVAL {0} DAY", req.maxage) : "",
                                             req.minsize > 0 ? String.Format("AND r.Size >= {0}'", req.minsize) : ""
                                             );

                var baseSql = String.Format(String.Concat(
                                                "SELECT r.*, ",
                                                "concat(cp.title, ' > ', c.title) AS category_name, ",
                                                "g.name AS group_name ",
                                                "FROM NZB r ",
                                                String.IsNullOrEmpty(req.q) ? "" :  "INNER JOIN NZBSearch rse ON rse.id = r.Id ",
                                                "LEFT JOIN `Group` g ON g.id = r.GroupId ",
                                                "LEFT JOIN Category c ON c.id = r.CategoryId ",
                                                "LEFT JOIN Category cp ON cp.id = c.parentid "
                                                ));


                if (!String.IsNullOrEmpty(req.q) && (req.q.Contains("blade") || req.q.Contains("sniper")))
                {
                    whereSql += "AND 0=1 ";
                }

                var sql = String.Format(String.Concat(
                                            "{0} ",
                                            "{1} ORDER BY r.PostDate DESC LIMIT {2} OFFSET {3} "
                                            ), baseSql, whereSql, req.limit > 0 ? (req.limit > 100 ? 100 : req.limit) : 100, req.offset);

                if (String.IsNullOrEmpty(req.q))
                {
                    total = Db.Scalar <int>(String.Format(String.Concat(
                                                              "SELECT SUM(Count) ",
                                                              "FROM Count r WHERE 1=1 ",
                                                              "{0} "), catsrch));
                }
                else
                {
                    total = Db.Scalar <int>(String.Format(String.Concat(
                                                              "SELECT count(*) ",
                                                              "FROM NZB r INNER JOIN NZBSearch rse ON rse.id = r.Id ",
                                                              "{0} "), whereSql));
                }

                results = Db.Select <NZBResult>(sql);
            }
            else if (function == "m") /* ------------------------------------------------------- */
            {
                int imdbId = -1;

                // don't return anything if it's an invalid id
                if (!string.IsNullOrEmpty(req.imdbid) && !int.TryParse(req.imdbid, out imdbId))
                {
                    return(getResults(results, total, req.offset, key, req));
                }

                string catsrch = GetCatSearch(Db, req.cat);

                var whereSql = String.Format(String.Concat(
                                                 "WHERE 1=1 ",
                                                 "{0} {1} {2} {3} {4} "),
                                             !String.IsNullOrEmpty(req.q) ? GetSphinxSearch(req.q) : "",
                                             (imdbId != -1 ? String.Format(" AND imdbid = {0} ", imdbId.ToString().PadLeft(7, '0')) : ""),
                                             catsrch,
                                             req.maxage > 0 ? String.Format("AND r.PostDate > NOW() - INTERVAL {0} DAY", req.maxage) : "",
                                             req.minsize > 0 ? String.Format("AND r.Size >= {0}'", req.minsize) : ""
                                             );

                var baseSql = String.Format(String.Concat(
                                                "SELECT r.*, ",
                                                "concat(cp.title, ' > ', c.title) AS category_name, ",
                                                "g.name AS group_name ",
                                                "FROM NZB r ",
                                                String.IsNullOrEmpty(req.q) ? "" : "INNER JOIN NZBSearch rse ON rse.id = r.Id ",
                                                "LEFT JOIN `Group` g ON g.id = r.GroupId ",
                                                "LEFT JOIN Category c ON c.id = r.CategoryId ",
                                                "LEFT JOIN Category cp ON cp.id = c.parentid "
                                                ));

                var sql = String.Format(String.Concat(
                                            "{0} ",
                                            "{1} ORDER BY r.PostDate DESC LIMIT {2} OFFSET {3} "
                                            ), baseSql, whereSql, req.limit > 0 ? (req.limit > 100 ? 100 : req.limit) : 100, req.offset);

                if (String.IsNullOrEmpty(req.q) && imdbId == -1)
                {
                    total = Db.Scalar <int>(String.Format(String.Concat(
                                                              "SELECT SUM(Count) ",
                                                              "FROM Count r WHERE 1=1 ",
                                                              "{0} "), catsrch));
                }
                else
                {
                    total = Db.Scalar <int>(String.Format(String.Concat(
                                                              "SELECT count(z.id) FROM (SELECT r.id FROM NZB r INNER JOIN NZBSearch rse ON rse.id = r.Id {0} LIMIT 125000) z "), whereSql));
                }

                results = Db.Select <NZBResult>(sql);
            }
            else if (function == "tv") /* ------------------------------------------------------- */
            {
                var airdate = "";
                var series  = "";
                var episode = "";
                // Process season only queries or Season and Episode/Airdate queries
                if (!String.IsNullOrEmpty(req.season) && !String.IsNullOrEmpty(req.ep))
                {
                    if (Regex.IsMatch(req.season, @"(19|20)\d{2}") && req.ep.Contains(@"/"))
                    {
                        var regex = new Regex(@"(19|20)\d{2}").Match(req.season);
                        airdate = (regex.Groups[0] + "-" + req.ep).Replace('/', '-');//str_replace('/', '-', $year[0] . '-' . $_GET['ep']);
                    }
                    else
                    {
                        series  = req.season;
                        episode = req.ep;
                    }
                }
                else if (!String.IsNullOrEmpty(req.season))
                {
                    series  = req.season;
                    episode = (!String.IsNullOrEmpty(req.ep) ? req.ep : "");
                }


                var  query        = "";
                var  siteSQL      = new List <string>();
                var  showSql      = "";
                bool validShowIds = true;

                var siteIdArr = new Dictionary <string, string>()
                {
                    { "id", !String.IsNullOrEmpty(req.vid) ? req.vid : "0" },
                    { "tvdb", !String.IsNullOrEmpty(req.tvdbid) ? req.tvdbid : "0" },
                    { "trakt", !String.IsNullOrEmpty(req.traktid) ? req.traktid : "0" },
                    { "tvrage", !String.IsNullOrEmpty(req.rid) ? req.rid : "0" },
                    { "tvmaze", !String.IsNullOrEmpty(req.tvmazeid) ? req.tvmazeid : "0" },
                    { "imdb", !String.IsNullOrEmpty(req.imdbid) ? req.imdbid : "0" },
                    { "tmdb", !String.IsNullOrEmpty(req.tmdbid) ? req.tmdbid : "0" }
                };

                foreach (var val in siteIdArr)
                {
                    int id = 0;

                    if (!int.TryParse(val.Value, out id))
                    {
                        validShowIds = false;
                    }

                    if (id > 0)
                    {
                        siteSQL.Add(String.Format("{0} = {1} ", val.Key, id));
                    }
                    //siteSQL += String.Format("OR {0} = {1} ", val.Key, id);
                }

                if (siteSQL.Count > 0)
                {
                    int episodeInt = 0;
                    int seriesInt  = 0;
                    int.TryParse(new Regex(@"^s0*", RegexOptions.IgnoreCase).Replace(series, ""), out seriesInt);
                    int.TryParse(new Regex(@"^e0*", RegexOptions.IgnoreCase).Replace(episode, ""), out episodeInt);

                    var showQuery = String.Format(String.Concat(
                                                      "SELECT ",
                                                      "v.id AS video, ",
                                                      "CAST(GROUP_CONCAT(tve.id SEPARATOR ',') AS CHAR) AS episodes ",
                                                      "FROM Video v ",
                                                      "LEFT JOIN TVEpisode tve ON v.id = tve.videos_id ",
                                                      "WHERE ({0}) {1} {2} {3} ",
                                                      "GROUP BY v.id "),
                                                  siteSQL.Join(" OR "),
                                                  !String.IsNullOrEmpty(series) ? String.Format("AND tve.series = {0}", seriesInt) : "",
                                                  !String.IsNullOrEmpty(episode) ? String.Format("AND tve.episode = {0}", episodeInt) : "",
                                                  !String.IsNullOrEmpty(airdate) ? String.Format("AND DATE(tve.firstaired) = '{0}'", esc(airdate)) : ""
                                                  );
                    //return new HttpResult(showQuery);
                    var show = Db.Single <ShowNZB>(showQuery);
                    if (show != null)
                    {
                        if ((!String.IsNullOrEmpty(series) || !String.IsNullOrEmpty(episode) || !String.IsNullOrEmpty(airdate)) && show.episodes.Length > 0)
                        {
                            showSql = String.Format(" AND r.TVEpisodeId IN ({0}) ", show.episodes);
                        }
                        else if (show.video > 0)
                        {
                            showSql = " AND r.VideoId = " + show.video + " ";
                            // If $series is set but episode is not, return Season Packs only
                            if (!String.IsNullOrEmpty(series) && String.IsNullOrEmpty(episode))
                            {
                                showSql += " AND r.tv_episodes_id = 0 ";
                            }
                        }
                        else
                        {
                            // If we were passed Episode Info and no match was found, do not run the query
                            return(getResults(results, total, req.offset, key, req));
                        }
                    }
                    else
                    {
                        // If we were passed Site ID Info and no match was found, do not run the query
                        return(getResults(results, total, req.offset, key, req));
                    }
                }
                // no valid ids found, return nil
                else if (siteSQL.Count == 0 && !validShowIds)
                {
                    return(getResults(results, total, req.offset, key, req));
                }

                // If $name is set it is a fallback search, add available SxxExx/airdate info to the query
                if (!String.IsNullOrEmpty(req.q) && showSql == "")
                {
                    int seriesInt = 0;
                    int.TryParse(series, out seriesInt);
                    if (!String.IsNullOrEmpty(series) && seriesInt < 1900)
                    {
                        req.q += String.Format(" S{0}", series.PadLeft(2, '0'));
                        if (!String.IsNullOrEmpty(episode) && !episode.Contains(@"/"))
                        {
                            req.q += String.Format("E{0}", episode.PadLeft(2, '0'));
                        }
                    }
                    else if (!String.IsNullOrEmpty(airdate))
                    {
                        req.q += String.Format(" {0}",
                                               airdate.Replace(@"/", " ")
                                               .Replace("-", " ")
                                               .Replace(".", " ")
                                               .Replace("_", " "));
                    }
                }


                string catsrch = GetCatSearch(Db, req.cat);

                string whereSql = String.Format(String.Concat(
                                                    "WHERE 1=1 ",
                                                    "{0} ",
                                                    "{1} {2} {3} {4} "),
                                                !String.IsNullOrEmpty(req.q) ? GetSphinxSearch(req.q) : "",
                                                catsrch,
                                                showSql,
                                                req.maxage > 0 ? String.Format("AND r.PostDate > NOW() - INTERVAL {0} DAY", req.maxage) : "",
                                                req.minsize > 0 ? String.Format("AND r.Size >= {0}'", req.minsize) : ""
                                                );

                query = String.Format(String.Concat(
                                          "SELECT r.*,",
                                          "v.title, v.countries_id, v.started, v.tvdb, v.trakt,",
                                          "    v.imdb, v.tmdb, v.tvmaze, v.tvrage, v.source,",
                                          "tve.series, tve.episode, tve.se_complete, tve.title, tve.firstaired, tve.summary, ",
                                          "CONCAT(cp.title, ' > ', c.title) AS category_name, ",
                                          "Group.name AS group_name ",
                                          "FROM NZB r ",
                                          String.IsNullOrEmpty(req.q) ? "" : "INNER JOIN NZBSearch rse ON rse.id = r.Id ",
                                          "LEFT OUTER JOIN Video v ON r.VideoId = v.id AND v.type = 0 ",
                                          "LEFT OUTER JOIN TVEpisode tve ON r.TVEpisodeId = tve.id ",
                                          "LEFT JOIN Category c ON c.id = r.CategoryId ",
                                          "LEFT JOIN Category cp ON cp.id = c.parentid ",
                                          "LEFT JOIN `Group` ON `Group`.id = r.GroupId ",
                                          "{0} ORDER BY PostDate DESC LIMIT {1} OFFSET {2} "),
                                      whereSql, req.limit > 0 ? (req.limit > 100 ? 100 : req.limit) : 100, req.offset);

                results = Db.Select <NZBResult>(query);

                if (String.IsNullOrEmpty(req.q) && String.IsNullOrEmpty(showSql))
                {
                    total = Db.Scalar <int>(String.Format(String.Concat(
                                                              "SELECT SUM(Count) ",
                                                              "FROM Count r WHERE 1=1 ",
                                                              "{0} "), catsrch));
                }
                else
                {
                    total = Db.Scalar <int>(String.Format(String.Concat(
                                                              "SELECT count(z.id) FROM (SELECT r.id FROM NZB r ",
                                                              "INNER JOIN NZBSearch rse ON rse.id = r.Id ",
                                                              "LEFT OUTER JOIN Video v ON r.VideoId = v.id AND v.type = 0 ",
                                                              "LEFT OUTER JOIN TVEpisode tve ON r.TVEpisodeId = tve.id {0} LIMIT 125000) z "
                                                              ), whereSql));
                }
            }
            else if (function == "g") /* ------------------------------------------------------- */
            {
                var nzb = Db.Single <NZB>(q => q.Guid == req.id);

                using (var db = ConnectionFactory.OpenDbConnection())
                {
                    db.Insert <Download>(new Download()
                    {
                        NZBId     = nzb.Id,
                        APIKeyId  = key.Id,
                        IPAddress = Request.Headers["X-Forwarded-For"],
                    });
                }

                var nzbpath = String.Format("nzb/{0}/{1}/{2}/{3}/",
                                            req.id[0],
                                            req.id[1],
                                            req.id[2],
                                            req.id[3]);
                var filename = String.Format("{0}.nzb.gz", req.id);
                var path     = _settings.Get <string>("FSPath");

                Stream stream = null;

                // check if nzb is stored in cache, else get from virt files (S3)
                if (!Directory.Exists(path + nzbpath) || !File.Exists(path + filename))
                {
                    var file = VirtualFiles.GetFile(nzbpath + filename);
                    Directory.CreateDirectory(path + nzbpath);
                    File.WriteAllBytes(path + nzbpath + filename, file.ReadAllBytes());
                }
                stream = File.OpenRead(path + nzbpath + filename);

                Response.AddHeader("Content-Disposition", "attachment; filename=" + nzb.Name + ".nzb");

                // decompress gzip
                MemoryStream output = new MemoryStream();

                using (Stream originalFileStream = stream)
                {
                    using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
                    {
                        decompressionStream.CopyTo(output);
                    }
                }

                return(new HttpResult(output, "application/x-nzb"));
            }

            return(getResults(results, total, req.offset, key, req));
        }