private static Embed CreateEmbed(AnnounceModel announceModel)
        {
            var title        = announceModel.AnimeGuildModel.AnimeTitle;
            var embedBuilder = new EmbedBuilder()
                               .WithTitle($"Episode {announceModel.Episode} of {title.EnglishTitle ?? title.RomajiTitle} just came out!");

            var links = new StringBuilder();

            foreach (var q in announceModel.QualityLinks)
            {
                if (q.Value.Link == null)
                {
                    continue;
                }

                string subgroup = q.Value.Subgroup == null ? "" : $"[{q.Value.Subgroup}]";
                links.AppendLine($"[{subgroup} - {QualityString.GetQualityString(q.Key)}]({q.Value.Link})");
            }

            string imageLink = null;

            try
            {
                var images = DuckDuckGoImageSearch.SearchImage(announceModel.AnimeGuildModel.AnimeTitle.RomajiTitle);
                imageLink = images[Program.Randomizer.Next(images.Length)];
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            var quote = Quotes.AnnounceQuotes.GetRandomQuote(announceModel.AnimeGuildModel.Guild);

            if (quote != null)
            {
                embedBuilder.AddField(x =>
                {
                    x.Name  = $"Wise words of {quote.Author}";
                    x.Value = quote.Message;
                });
            }

            if (imageLink != null)
            {
                embedBuilder.ImageUrl = imageLink;
            }
            embedBuilder.Description = links.ToString();
            embedBuilder.Color       = new Color(255, 255, 255);

            return(embedBuilder.Build());
        }
        private static async Task AnnounceEdit(AnnounceModel announceModel)
        {
            var originalEmbed = announceModel.AnnouncedMessage.Embeds.First();
            var embed         = CreateEmbed(announceModel);

            embed = originalEmbed.ToEmbedBuilder().WithDescription(embed.Description).Build();

            if (!AnnouncedAnime.TryGetValue(announceModel.AnimeGuildModel.AnimeID, out var model) ||
                model.AnnouncedMessage == null)
            {
                return;
            }

            await model.AnnouncedMessage.ModifyAsync(x => x.Embed = embed);
        }
        public static void UpdateAnime(AnnounceModel announceModel)
        {
            if (!AnnouncedAnime.ContainsKey(announceModel.AnimeGuildModel.AnimeID))
            {
                // If it doesn't contain the key, it's very simple. Just add it,
                // and then add the self destruct anonymous method.

                // check if the subgroup is even correct
                var(subgroup, _, _) = GetSubgroupFromAnnounceModel(announceModel);

                if (subgroup == null || !announceModel.AnimeGuildModel
                    .WantedSubgroupTitle.Select(x => x.ToLower())
                    .Contains(subgroup.ToLower()))
                {
                    return;
                }

                AnnouncedAnime.Add(announceModel.AnimeGuildModel.AnimeID, announceModel);
                Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(TimeSpan.FromMinutes(20));
                    AnnouncedAnime.Remove(announceModel.AnimeGuildModel.AnimeID);
                }).ConfigureAwait(false);
            }
            else
            {
                // If it does contain the key, it's a bit harder..
                var a = AnnouncedAnime[announceModel.AnimeGuildModel.AnimeID];

                // Get the important subgroup. the parameter announceModel
                // will have only 1 correct subgroup.
                // So we will get the current subgroup and the "new" subgroup and compare them against each other.
                // If the important subgroup equals the new subgroup, we edit the anime model to be that one. :))
                var    result      = GetSubgroupFromAnnounceModel(announceModel);
                string newSubgroup = result.Item1;
                if (result.quality == Quality.Unknown)
                {
                    return;
                }
                string currentSubgroup   = a.QualityLinks[result.quality].Subgroup;
                string importantSubgroup = GetImportantSubgroup(newSubgroup, currentSubgroup, a.AnimeGuildModel);

                if (string.Equals(importantSubgroup, newSubgroup, StringComparison.CurrentCultureIgnoreCase))
                {
                    a.QualityLinks[result.quality] = new SubgroupTorrentLink(result.link, result.subgroup);
                }
            }
        }
        public static void Announce(AnnounceModel model)
        {
            if (!AnnouncedAnime.TryGetValue(model.AnimeGuildModel.AnimeID, out var anime))
            {
                return;
            }

            if (anime.AnnouncedMessage != null)
            {
                AnnounceEdit(anime).ConfigureAwait(false);
            }
            else if (model.Episode > model.AnimeGuildModel.LastAnnouncedEpisode && anime.AnnouncedMessage == null)
            {
                AnnounceNew(model).Wait();
            }
        }
        private static async Task AnnounceNew(AnnounceModel model)
        {
            var embed    = CreateEmbed(model);
            var mentions = GetMentions(model.AnimeGuildModel);

            var client  = Program.ServiceProvider.GetRequiredService <DiscordSocketClient>();
            var guild   = client.GetGuild(model.AnimeGuildModel.Guild);
            var channel = guild?.GetTextChannel(model.AnimeGuildModel.Channel);

            if (channel == null)
            {
                return;                  // This would be very bad!!!
            }
            var message = await channel.SendMessageAsync(mentions, embed : embed);

            AnnouncedAnime[model.AnimeGuildModel.AnimeID].AnnouncedMessage = message;

            Quotes.AnnounceQuotes.AddQuoteWaiter(model.AnimeGuildModel);
        }
        /// <summary>
        /// This method is only for temporary models, which are created by the checker.
        /// It will find the first correct Quality link where the subgroup is not null, and return it.
        /// </summary>
        private static (string subgroup, Quality quality, string link) GetSubgroupFromAnnounceModel(AnnounceModel announceModel)
        {
            foreach (var q in announceModel.QualityLinks)
            {
                if (q.Value.Link != null)
                {
                    return(q.Value.Subgroup, q.Key, q.Value.Link);
                }
            }

            return(null, Quality.Unknown, null);  // I mean... this should theoratically not happen... but ehh...
        }
        /// <summary>
        /// Performs the actual check for the anime
        /// </summary>
        /// <returns>true if something has been found</returns>
        public static async Task <bool> Check()
        {
            // get the XML, and parse it
            var xml = await NyaaRSSFeed.GetRSSFeed();

            var parsedXML = NyaaXMLConverter.ParseXML(xml);

            NyaaTorrentModel[] rawTorrents = NyaaXMLConverter.GetTorrents(parsedXML);

            string lastChecked = Database.Database.GetLastChecked();

            ParsedNyaaTorrentModel[] parsedTorrents = NyaaParser.ParseNyaaTorrents(rawTorrents)
                                                      .TakeWhile(x => x.NyaaTorrentModel.InfoHash != lastChecked).ToArray();

            // if the list is empty, return false.
            if (parsedTorrents.Length == 0)
            {
                return(false);
            }

            // set the lastChecked to the first occurence fiaojfoiasoi jdsfjsdoif doisf
            Database.Database.SetLastChecked(parsedTorrents[0].NyaaTorrentModel.InfoHash);


            // get ALL EPIC ANIME
            var(_, collection) = Database.Database.GetDatabaseAndSubscriptionCollection();

            var guildAnimes     = collection.FindAll().ToList();
            var animeToAnnounce = new List <AnnounceModel>();

            bool foundSomething = false;

            foreach (var parsedTorrent in parsedTorrents)
            {
                // if the title is correct, add it to the update list.
                var validAnime = guildAnimes.Where(x =>
                {
                    bool valid = true;

                    const double minSim = 0.55;

                    double confidence = Math.Max(
                        (x.AnimeTitle.EnglishTitle ?? "").ToLower().GetSimilarity((parsedTorrent.AnimeTitle ?? "").ToLower()),
                        x.AnimeTitle.RomajiTitle.ToLower().GetSimilarity((parsedTorrent.AnimeTitle ?? "").ToLower()));

                    valid = confidence >= minSim;

                    valid = valid && x.WantedSubgroupTitle.Contains(parsedTorrent.SubGroup.ToLower());

                    valid = valid && parsedTorrent.Episode >= x.LastAnnouncedEpisode;

                    return(valid);
                });

                foreach (var anime in validAnime)
                {
                    var m = new AnnounceModel()
                    {
                        AnimeGuildModel = anime,
                        Episode         = parsedTorrent.Episode
                    };

                    if (parsedTorrent.Quality != Quality.Unknown)
                    {
                        m.QualityLinks[parsedTorrent.Quality] = new SubgroupTorrentLink(parsedTorrent.NyaaTorrentModel.Link,
                                                                                        parsedTorrent.SubGroup);
                    }

                    if (!animeToAnnounce.Any(x => x.AnimeGuildModel.AnimeID == anime.AnimeID &&
                                             animeToAnnounce.Any(y => y.AnimeGuildModel.Guild == x.AnimeGuildModel.Guild)))
                    {
                        animeToAnnounce.Add(m);
                    }
                    AnimeReminderAnnouncer.UpdateAnime(m);

                    foundSomething = true;
                }
            }

            foreach (var anime in animeToAnnounce)
            {
                AnimeReminderAnnouncer.Announce(anime);
                anime.AnimeGuildModel.LastAnnouncedEpisode = anime.Episode;
                collection.Update(anime.AnimeGuildModel);
            }

            return(foundSomething);
        }
Пример #8
0
        //
        // GET: /Announce/Announce/
        // GET: /announce/123af0c917876f6d4711654b2293895f
        public ActionResult Announce(AnnounceModel announceModel)
        {
            if (!announceModel.IsValidRequest())
            {
                return(new BTErrorResult("Invalid request (see specification: http://bit.ly/bcYmSu)"));
            }

            if (!Regex.IsMatch(announceModel.Passkey, "[0-9a-fA-F]{32}"))
            {
                return(new BTErrorResult("Invalid passkey."));
            }

            if (BLACKLIST_PORTS && IsPortBlackListed(Convert.ToInt32(announceModel.port)))
            {
                return(new BTErrorResult(string.Format("Port {0} is blacklisted", announceModel.port)));
            }

            try
            {
                using (var context = new OpenTrackerDbContext())
                {
                    var crntUser = (from u in context.users
                                    where u.passkey == announceModel.Passkey
                                    select u).Take(1).FirstOrDefault();
                    if (crntUser == null)
                    {
                        return(new BTErrorResult(string.Format("Unknown passkey. Please re-download the torrent from {0}.",
                                                               TrackerSettings.BASE_URL)));
                    }

                    if (crntUser.activated == 0)
                    {
                        return(new BTErrorResult("Permission denied, you\'re not activated."));
                    }

                    var seeder = false;
                    if (announceModel.left == 0)
                    {
                        seeder = true;
                    }

                    // Entity Framework does not support BINARY keys
                    var EncodedPeerId   = Convert.ToBase64String(Encoding.ASCII.GetBytes(announceModel.peer_id));
                    var EncodedInfoHash = BEncoder.FormatUrlInfoHash();

                    var torrentExist = (from t in context.torrents
                                        where t.info_hash == EncodedInfoHash
                                        select t).Take(1).FirstOrDefault();
                    if (torrentExist == null)
                    {
                        return(new BTErrorResult("Torrent not registered with this tracker."));
                    }

                    var peerAlreadyExist = (from t in context.peers
                                            where t.torrentid == torrentExist.id &&
                                            t.peer_id == EncodedPeerId &&
                                            t.passkey == announceModel.Passkey
                                            select t).Take(1);
                    var   existingPeerCount = peerAlreadyExist.Count();
                    peers p;
                    if (existingPeerCount == 1)
                    {
                        p = peerAlreadyExist.First();
                    }
                    else
                    {
                        var connectionLimit = (from t in context.peers
                                               where t.torrentid == torrentExist.id &&
                                               t.passkey == announceModel.Passkey
                                               select t).Count();
                        if (connectionLimit >= 1 && !seeder)
                        {
                            return(new BTErrorResult("Connection limit exceeded! " +
                                                     "You may only leech from one location at a time."));
                        }
                        if (connectionLimit >= 3 && seeder)
                        {
                            return(new BTErrorResult("Connection limit exceeded."));
                        }


                        if (announceModel.left > 0 && crntUser.@class < (decimal)AccountValidation.Class.Administrator)
                        {
                            var epoch   = Unix.ConvertToUnixTimestamp(DateTime.UtcNow);
                            var elapsed = Math.Floor((epoch - torrentExist.added) / 3600);

                            var uploadedGigs = crntUser.uploaded / (1024 * 1024 * 1024);
                            var ratio        = ((crntUser.downloaded > 0) ? (crntUser.uploaded / crntUser.downloaded) : 1);

                            int wait;
                            if (ratio < (decimal)0.5 || uploadedGigs < 5)
                            {
                                wait = 48;
                            }
                            else if (ratio < (decimal)0.65 || uploadedGigs < (decimal)6.5)
                            {
                                wait = 24;
                            }
                            else if (ratio < (decimal)0.8 || uploadedGigs < 8)
                            {
                                wait = 12;
                            }
                            else if (ratio < (decimal)0.95 || uploadedGigs < (decimal)9.5)
                            {
                                wait = 6;
                            }
                            else
                            {
                                wait = 0;
                            }

                            if (elapsed < wait)
                            {
                                return(new BTErrorResult(string.Format("Not authorized (wait {0}h) - READ THE FAQ!",
                                                                       (wait - elapsed))));
                            }
                        }

                        p = new peers
                        {
                            torrentid = torrentExist.id,
                            peer_id   = EncodedPeerId,
                            userid    = crntUser.id,
                            passkey   = announceModel.Passkey,
                            useragent = Request.UserAgent
                        };
                    }

                    var remoteHost = Request.ServerVariables["REMOTE_HOST"];
                    var ip         = !string.IsNullOrEmpty(announceModel.ip) ? announceModel.ip : remoteHost;

                    if (CHECK_CONNECTABLE)
                    {
                        p.connectable = IsConnectable(ip, Convert.ToInt32(announceModel.port)) ? 1 : 0;
                    }
                    if (announceModel.left != null)
                    {
                        p.left = (decimal)announceModel.left;
                    }
                    p.port = Convert.ToInt32(announceModel.port);
                    p.ip   = ip;

                    p.seeding = seeder ? 1 : 0;

                    if (existingPeerCount == 0)
                    {
                        context.AddTopeers(p);
                    }
                    else
                    {
                        if (crntUser.@class < (decimal)AccountValidation.Class.Administrator)
                        {
                            var nonUpdatedPeer = peerAlreadyExist.First();
                            var thisUploaded   = (announceModel.uploaded - nonUpdatedPeer.uploaded);
                            var thisDownloaded = (announceModel.downloaded - nonUpdatedPeer.downloaded);

                            p.uploaded   += (decimal)thisUploaded;
                            p.downloaded += (decimal)thisDownloaded;

                            if (thisUploaded > 0)
                            {
                                crntUser.uploaded = (crntUser.uploaded + Convert.ToInt64(thisUploaded));
                            }
                            if (thisDownloaded > 0)
                            {
                                crntUser.downloaded = (crntUser.downloaded + Convert.ToInt64(thisDownloaded));
                            }
                        }

                        if (announceModel.Event == "completed")
                        {
                            torrentExist.snatches = torrentExist.snatches + 1;                             // torrentExist.snatches++;
                        }
                    }
                    context.SaveChanges();

                    if (announceModel.Event == "stopped")
                    {
                        var removePeer = (from pr in context.peers
                                          where pr.torrentid == torrentExist.id &&
                                          pr.peer_id == EncodedPeerId
                                          select pr).Take(1).FirstOrDefault();
                        context.peers.DeleteObject(removePeer);
                        context.SaveChanges();

                        var announceResultStop = new AnnounceResult
                        {
                            Interval = ANNOUNCE_INTERVAL
                        };
                        return(announceResultStop);
                    }

                    var announceResult = new AnnounceResult
                    {
                        Interval = ANNOUNCE_INTERVAL
                    };

                    var existingPeers = (from t in context.peers
                                         where t.torrentid == torrentExist.id
                                         select t).ToList();

                    foreach (var peer in existingPeers)
                    {
                        announceResult.AddPeer(peer.peer_id, peer.ip, peer.port);
                    }

                    return(announceResult);
                }
            }
            catch (Exception)
            {
                return(new BTErrorResult("Database unavailable"));
            }
        }