public async Task ProcessAsync(Sisters.WudiLib.Posts.Message message, HttpApiClient api)
        {
            // TODO 验证用户名是否合法
            var(success, userInfo) = await OsuApi.GetUserInfoAsync(_userName, OsuMixedApi.Mode.Standard);

            if (!success)
            {
                await api.SendMessageAsync(message.Endpoint, "网络错误。");

                return;
            }
            if (userInfo == null)
            {
                await api.SendMessageAsync(message.Endpoint, "没有此用户。");

                return;
            }
            var dbResult = await Database.AddNewBindAsync(message.UserId, userInfo.Id, userInfo.Name, "自己绑定", message.UserId, userInfo.Name);

            if (dbResult.Success)
            {
                await api.SendMessageAsync(message.Endpoint, $"成功绑定为{userInfo.Name}。");
            }
            else if (dbResult.Exception is DbUpdateException && dbResult.Exception.InnerException?.Message.Contains("Duplicate", StringComparison.Ordinal) == true)
            {
                await api.SendMessageAsync(message.Endpoint, "在已绑定的情况下不允许修改,如需修改请联系 bleatingsheep。");
            }
            else
            {
                await api.SendMessageAsync(message.Endpoint, "数据库访问错误。");

                FLogger.LogException(dbResult.Exception);
            }
        }
Exemple #2
0
        public override object CommandHandler(SocketMessage socketMessage, string input, CommandArguments arguments)
        {
            if (string.IsNullOrEmpty(input) || input.Length <= 3)
            {
                return("Please enter a username to connect to");
            }

            OsuUser osuUser = OsuApi.GetUser(input);

            if (osuUser == null)
            {
                return("Unable to find any user with this username");
            }

            InternalUser internalUser = DatabaseManager.Instance.GetUser(socketMessage.Author.Id);

            if (string.IsNullOrEmpty(internalUser.OsuUserID))
            {
                internalUser.OsuUserID = osuUser.ID.ToString();
                return("Registered '" + osuUser.Name + "' to your profile, " + socketMessage.Author.Mention);
            }
            else
            {
                internalUser.OsuUserID = osuUser.ID.ToString();
                return("Changed connection to '" + osuUser.Name + "' on your profile, " + socketMessage.Author.Mention);
            }
        }
Exemple #3
0
        public Beatmap(Input input)
        {
            if (input.BeatmapId == null)
            {
                throw new Exception("No beatmap link provided");
            }

            Task <BeatmapData[]> beatmapRequest     = OsuApi.Beatmap(input.BeatmapId, input.ModRequestNumber ?? 0, input.Gamemode);
            Task <ScoreData[]>   leaderboardRequest = OsuApi.Leaderboard(input.BeatmapId, input.Gamemode);

            Task.WhenAll(
                beatmapRequest,
                leaderboardRequest
                ).Wait();

            beatmap     = beatmapRequest.Result[0];
            leaderboard = leaderboardRequest.Result;

            CountLeaderboardFullCombo();

            difficultyCalculator = new DifficultyCalculator(input.BeatmapId, input.Gamemode, input.ModNumber);
            difficulty           = difficultyCalculator.Calculate();

            Embed = CreateEmbed();
        }
        protected async Task <UserInfo> EnsureGetUserInfo(string name, Bleatingsheep.Osu.Mode mode)
        {
            var(success, result) = await OsuApi.GetUserInfoAsync(name, mode);

            ExecutingException.Ensure(success, "网络错误。");
            ExecutingException.Ensure(result != null, "无此用户!");
            return(result);
        }
        //Prepare a new session
        public void PrepareSession(Session session = null)
        {
            SessionThread?.Join();

            if (session == null)
            {
                CurrentSession = new Session
                {
                    Username = SettingsManager.Instance.Settings["api"]["user"]
                };
            }
            else
            {
                CurrentSession = session;
            }

            if (CurrentSession.ReadOnly)
            {
                OsuUser currentUserData = null;
                try
                {
                    currentUserData = OsuApi.GetUser(CurrentSession.Username, (OsuMode)Enum.Parse(typeof(OsuMode), SettingsManager.Instance.Settings["api"]["gamemode"]));
                }
                catch (Exception)
                {
                    BrowserViewModel.Instance.SendNotification(NotificationType.Danger, StringStorage.Get("Message.UserDataError"));
                    return;
                }
                BrowserViewModel.Instance.ApplySession(CurrentSession);
                BrowserViewModel.Instance.ApplyUser(currentUserData);

                StopProgressHandler();
                BrowserViewModel.Instance.AttachedJavascriptWrapper.Hide("#sessionProgressTime");
                BrowserViewModel.Instance.AttachedJavascriptWrapper.Show("#sessionProgressReadonly");

                string startDate = DateTimeOffset.FromUnixTimeSeconds(CurrentSession.SessionDate).ToString("MMMM dd yyyy HH:mm:ss");
                string endDate   = DateTimeOffset.FromUnixTimeSeconds(CurrentSession.SessionEndDate).ToString("MMMM dd yyyy HH:mm:ss");

                BrowserViewModel.Instance.AttachedJavascriptWrapper.SetHtml("#sessionProgressReadonlyText", startDate + " to " + endDate);
            }
            else
            {
                SessionThread = new ExtendedThread(() => OnUpdate(), Convert.ToInt32(SettingsManager.Instance.Settings["api"]["updateRate"]));

                lastIteration = DateTimeOffset.Now.ToUnixTimeSeconds();
                nextIteration = DateTimeOffset.Now.ToUnixTimeSeconds() + SessionThread.SleepTime;

                StartProgressHandler();
                SessionThread.Start();

                BrowserViewModel.Instance.AttachedJavascriptWrapper.Hide("#sessionProgressReadonly");

                if (SettingsManager.Instance.Settings["display"]["showTimer"] == "true")
                {
                    BrowserViewModel.Instance.AttachedJavascriptWrapper.Show("#sessionProgressTime");
                }
            }
        }
Exemple #6
0
        public async Task User(CommandContext ctx)
        {
            ctx.TriggerTypingAsync();
            //add mod data in top plays
            var      input    = new Input(ctx.Message);
            UserData userData = await OsuApi.User(input);

            var user = new User(input, userData);
            await ctx.Channel.SendMessageAsync(embed : user.Embed);
        }
Exemple #7
0
        public async Task Best(CommandContext ctx)
        {
            ctx.TriggerTypingAsync();
            var input = new Input(ctx.Message);

            ScoreData[] scoreData = await OsuApi.Score(input);

            var score = new Score(input, scoreData);
            await ctx.Channel.SendMessageAsync(embed : score.Embed);
        }
        public async Task <bool> Init(string[] args)
        {
            var opts = new OptionSet()
            {
                { "d|dir=", "Set server storage dir (default: ./)", b => ServerDir = b },
                { "s|secret=", "Set client secret (osu!) (required)", s => OsuSecret = s },
                { "k|key=", "osu! api v1 key (required)", k => OsuApiKey = k },
                { "id=", "osu! client id (default: mine)", id => OsuId = id },
                { "t|token=", "discord bot token (required)", t => DiscordToken = t },
                { "h|help", "displays help", a => Help = a != null },
                { "l|link", "displays bot link and exits", l => Link = l != null },
                { "apiRequest=", "does api request", a => Apiv2Req = a },
                { "test", "test server only", t => Test = t != null },
                { "w|webhook=", "webhook for output", w => WebHook = w },
                { "reload", "reload databases", r => Reload = r != null },
            };

            opts.Parse(args);
            string botLink = $"https://discordapp.com/oauth2/authorize?client_id={DiscordId}&scope=bot&permissions={DiscordPermissions}";

            if (Link)
            {
                Console.WriteLine(botLink);
                return(false);
            }

            if (Help || (OsuSecret.Length * OsuApiKey.Length * DiscordToken.Length) == 0)
            {
                Console.WriteLine(
                    $@"osu! Miss Analyzer, Discord Bot Edition
Bot link: https://discordapp.com/oauth2/authorize?client_id={DiscordId}&scope=bot&permissions={DiscordPermissions}");
                opts.WriteOptionDescriptions(Console.Out);
                return(false);
            }
            if (Apiv2Req != null)
            {
                OsuApi api2 = new OsuApi(ServerContext.webClient, OsuId, OsuSecret, OsuApiKey);
                Console.WriteLine(await api2.GetApiv2(Apiv2Req));
                return(false);
            }

            try
            {
                using (var stream = Assembly.GetEntryAssembly().GetManifestResourceStream("OsuMissAnalyzer.Server.Resources.GitCommit.txt"))
                    using (var streamReader = new StreamReader(stream, Encoding.UTF8))
                    {
                        GitCommit = streamReader.ReadToEnd();
                    }
            }
            catch (Exception) { return(false); }

            return(true);
        }
        public async Task ProcessAsync(Message message, Sisters.WudiLib.HttpApiClient api)
        {
            long id = message.UserId;

            var(networkSuccess, osuResult) = await DataProvider.GetBindingIdAsync(id);

            ExecutingException.Ensure(networkSuccess, "无法查询绑定账号。");
            ExecutingException.Ensure(osuResult != null, "未绑定 osu! 游戏账号。");

            var osuId  = osuResult.Value;
            var recent = (await OsuApi.GetRecentlyAsync(osuId, OsuMixedApi.Mode.Standard, 1)).FirstOrDefault();

            if (recent == null)
            {
                await api.SendMessageAsync(message.Endpoint, "没打图!");

                return;
            }

            var reply = new List <string> {
                "/np 给 bleatingsheep,查询更方便!"
            };

            try
            {
                var ppBeatmap = await s_spider.GetBeatmapPlusAsync(recent.BeatmapId);

                if (ppBeatmap == null)
                {
                    reply.Add("很抱歉,无法查询 Loved 图。也有可能是 PP+ 没有这张图的数据。");
                    return;
                }
                reply.Add($"https://syrin.me/pp+/b/{ppBeatmap.Id}/");
                reply.Add("Stars: " + ppBeatmap.Stars);
                reply.Add("Aim (Jump): " + ppBeatmap.AimJump);
                reply.Add("Aim (Flow): " + ppBeatmap.AimFlow);
                reply.Add("Precision: " + ppBeatmap.Precision);
                reply.Add("Speed: " + ppBeatmap.Speed);
                reply.Add("Stamina: " + ppBeatmap.Stamina);
                reply.Add("Accuracy: " + ppBeatmap.Accuracy);
                reply.Add("数据来自 PP+。");
            }
            catch (ExceptionPlus)
            {
                reply.Add("访问 PP+ 网站失败。");
            }
            finally
            {
                await api.SendMessageAsync(message.Endpoint, string.Join("\r\n", reply));
            }
        }
        private void GetUserInfoFromOsu()
        {
            if (userinfo_locked == 0)
            {
                if (bps == null)
                {
                    var mode = Displayer.Mode;

                    Interlocked.Increment(ref userinfo_locked);
                    userInfo = OsuApi.GetPlayerInfo(Displayer.Playername, mode);
                    Interlocked.Decrement(ref userinfo_locked);
                }
            }
        }
        private void GetBpFromOsu()
        {
            if (bps_locked == 0)
            {
                if (bps == null)
                {
                    var mode = Displayer.Mode;

                    Interlocked.Increment(ref bps_locked);
                    bps = OsuApi.GetBp(Displayer.Playername, mode);
                    Interlocked.Decrement(ref bps_locked);
                }
            }
        }
        public override object CommandHandler(SocketMessage socketMessage, string input, CommandArguments arguments)
        {
            ApplyMode(arguments);
            ApplyPlayer(socketMessage.Author.Id, input);

            if (_osuUser == null)
            {
                return("No user has been found.");
            }

            List <OsuPlay> recentPlays = OsuApi.GetUserRecent(_osuUser.Name, _osuMode, 1, true);

            if (recentPlays == null)
            {
                return("" + _osuUser.Name + " has not played in the last 24 hours");
            }

            OsuPlay recentPlay = recentPlays[0];

            EmbedBuilder embed = new EmbedBuilder()
            {
                Title       = "Most recent play by **" + _osuUser.Name + "** in osu!" + _osuMode,
                Description = "[" + recentPlay.Beatmap.Artist + " - " + recentPlay.Beatmap.Title + " \\[" + recentPlay.Beatmap.DifficultyName + "\\]](https://osu.ppy.sh/beatmaps/" + recentPlay.Beatmap.BeatmapID + ")\n" +
                              "Map status: " + OsuApi.BeatmapStatusEmotes[recentPlay.Beatmap.Status].ToString() + " " + recentPlay.Beatmap.Status.ToString(),
                ThumbnailUrl = "https://b.ppy.sh/thumb/" + recentPlay.Beatmap.BeatmapSetID + "l.jpg",
                Fields       = new List <EmbedFieldBuilder>()
                {
                    new EmbedFieldBuilder()
                    {
                        Name  = "Beatmap Information",
                        Value = "(" + Mathf.Round(recentPlay.Beatmap.Starrating ?? 0, 2) + "*) CS" + Mathf.Round(recentPlay.Beatmap.MapStats.CS, 2) + " • AR" + Mathf.Round(recentPlay.Beatmap.MapStats.AR, 2) + " • OD" + Mathf.Round(recentPlay.Beatmap.MapStats.OD, 2) + " • HP" + Mathf.Round(recentPlay.Beatmap.MapStats.HP, 2) + "\n" +
                                "Mapped by [" + recentPlay.Beatmap.Mapper + "](https://osu.ppy.sh/users/" + recentPlay.Beatmap.MapperID + ")",
                        IsInline = false
                    },
                    new EmbedFieldBuilder()
                    {
                        Name  = "Play Information",
                        Value = OsuRanks.GetEmojiFromRank(recentPlay.Rank).ToString() + " " + Mathf.Round(recentPlay.Accuracy, 2) + "% **+" + ("" + ((OsuModsShort)recentPlay.Mods).ModParser() + "").Replace(", ", "") + "** • **" + Mathf.Round(recentPlay.Performance.CurrentValue, 2) + "pp** " + recentPlay.MaxCombo + "x/" + recentPlay.Beatmap.MaxCombo + "x " + ((recentPlay.IsFullcombo == "1"?"":"(For FC: **" + Mathf.Round(recentPlay.Performance.CurrentValueIfFC, 2) + "pp**)")) + "\n" +
                                "[" + recentPlay.C300 + "/" + recentPlay.C100 + "/" + recentPlay.C50 + "/" + recentPlay.CMiss + "] • " + recentPlay.Score.FormatNumber(),
                        IsInline = false
                    }
                },
                Footer = new EmbedFooterBuilder()
                {
                    Text = "Played " + DateTime.Parse(recentPlay.DateAchieved).Humanize(),
                }
            };

            return(embed);
        }
Exemple #13
0
        public UserTopGenerator(string osuApiKey, MapCacher mapCacher)
        {
            if (mapCacher == null)
            {
                throw new ArgumentNullException(nameof(mapCacher));
            }
            if (string.IsNullOrEmpty(osuApiKey))
            {
                throw new ArgumentException("osuApiKey is required.");
            }

            _osuApi            = new OsuApi(osuApiKey);
            _mapCacher         = mapCacher;
            _collectionManager = new CollectionsManager(_mapCacher.Beatmaps);
        }
Exemple #14
0
        public async Task DiffGraph(CommandContext ctx)
        {
            ctx.TriggerTypingAsync();
            var input = new Input(ctx.Message);

            BeatmapData[] beatmapData = await OsuApi.Beatmap(input.BeatmapId ?? input.Page.ToString(), input.ModRequestNumber ?? 0, input.Gamemode);

            if (beatmapData.Length == 0)
            {
                throw new Exception("Beatmap not found");
            }

            var graph = new DifficultyGraph(input, beatmapData[0]);
            await ctx.Channel.SendFileAsync("graph.png", graph.ToStream());
        }
Exemple #15
0
        public async Task Link(CommandContext ctx, params string[] nameArgs)
        {
            ctx.TriggerTypingAsync();
            string osuName = string.Join(" ", nameArgs);

            if (string.IsNullOrEmpty(osuName))
            {
                throw new Exception("No name provided");
            }

            UserData osuUser = await OsuApi.User(osuName);

            await Database.SetOsuUser(ctx.Message.Author.Id, osuUser.UserId.ToString());

            await ctx.Channel.SendMessageAsync($"{ctx.Message.Author.Mention} has been linked to `{osuName}`");
        }
Exemple #16
0
        public async Task BadgeWeightedSeedingByUser(CommandContext ctx, int badgeCount, params string[] nameArgs)
        {
            int    rank = 0;
            string osuName;

            if (nameArgs.Length == 1)
            {
                int.TryParse(nameArgs[0], out rank);
            }

            if (rank == 0)
            {
                UserData osuUser;

                if (nameArgs.Length > 0)
                {
                    osuName = string.Join(" ", nameArgs).Replace("\"", "");
                    osuUser = await OsuApi.User(osuName);
                }
                else
                {
                    if (ctx.Message.MentionedUsers.Count > 0)
                    {
                        osuName = await Database.GetOsuUser(ctx.Message.MentionedUsers[0].Id);
                    }
                    else
                    {
                        osuName = await Database.GetOsuUser(ctx.Message.Author.Id);
                    }

                    osuUser = await OsuApi.User(int.Parse(osuName));
                }

                if (string.IsNullOrEmpty(osuName))
                {
                    throw new Exception("No username or rank provided");
                }

                await ctx.Channel.SendMessageAsync($"BWS rank for `{osuUser.Username}` with {badgeCount} badges is {Math.Round(Math.Pow(osuUser.PPRank, Math.Pow(0.9937, Math.Pow(badgeCount, 2))))}");
            }
            else
            {
                await ctx.Channel.SendMessageAsync($"BWS at rank `{rank}` with {badgeCount} badges is {Math.Round(Math.Pow(rank, Math.Pow(0.9937, Math.Pow(badgeCount, 2))))}");
            }
        }
Exemple #17
0
        protected void ApplyPlayer(ulong DiscordID, string input)
        {
            _osuUser = null;
            if (string.IsNullOrEmpty(input))
            {
                InternalUser internalUser = DatabaseManager.Instance.GetUser(DiscordID);
                if (!string.IsNullOrEmpty(internalUser.OsuUserID))
                {
                    _osuUser = OsuApi.GetUser(internalUser.OsuUserID, _osuMode);
                }
            }

            if (_osuUser == null)
            {
                string username = HttpUtility.HtmlEncode(input); // Test value
                _osuUser = OsuApi.GetUser(username, _osuMode);
            }
        }
        private void OnUpdate()
        {
            if (!NetworkManager.Instance.HasConnection())
            {
                BrowserViewModel.Instance.SendNotification(NotificationType.Warning, StringStorage.Get("Message.NoInternet"));
                return;
            }

            //BrowserViewModel.Instance.SendNotification(NotificationType.Success, "Test: session iteration");
            OsuUser currentUserData = null;

            try
            {
                currentUserData = OsuApi.GetUser(CurrentSession.Username, (OsuMode)Enum.Parse(typeof(OsuMode), SettingsManager.Instance.Settings["api"]["gamemode"]));
            }
            catch (Exception)
            {
                BrowserViewModel.Instance.SendNotification(NotificationType.Danger, StringStorage.Get("Message.UserDataError"));
            }

            if (currentUserData != null)
            {
                if (CurrentSession.InitialData == null)
                {
                    CurrentSession.InitialData = SessionData.FromUser(currentUserData);
                }

                CurrentSession.CurrentData    = SessionData.FromUser(currentUserData);
                CurrentSession.DifferenceData = CurrentSession.CurrentData - CurrentSession.InitialData;

                BrowserViewModel.Instance.ApplySession(CurrentSession);
                BrowserViewModel.Instance.ApplyUser(currentUserData);

                int updateRate = Convert.ToInt32(SettingsManager.Instance.Settings["api"]["updateRate"]);
                if (updateRate != SessionThread.SleepTime)
                {
                    SessionThread.SleepTime = updateRate;
                }
            }

            lastIteration = DateTimeOffset.Now.ToUnixTimeSeconds();
            nextIteration = DateTimeOffset.Now.ToUnixTimeSeconds() + SessionThread.SleepTime;
        }
        protected async Task <(bool, UserInfo)> GetCachedUserInfo(int id, Bleatingsheep.Osu.Mode mode)
        {
            var hasCache = s_cache.TryGetValue <UserInfo>((id, mode), out var cachedInfo);

            if (hasCache)
            {
                return(true, cachedInfo);
            }
            var(success, userInfo) = await OsuApi.GetUserInfoAsync(id, mode);

            if (success)
            {
                s_cache.Set((id, mode), userInfo, CacheAvailable);
                return(true, userInfo);
            }
            else
            {
                // fail
                return(default);
Exemple #20
0
        public DiscordEmbedBuilder CreateListEmbed()
        {
            this.user = OsuApi.User(input).Result;

            DiscordEmbedBuilder embed = CreateBaseEmbed();

            for (int i = input.Page * 5 - 5; i < input.Page * 5; i++)
            {
                if (i < scoreList.Length)
                {
                    ScoreData score = scoreList[i];

                    int         modRequestNumber = OsuHelper.GetModRequestNumber(score.EnabledMods);
                    BeatmapData beatmap          = OsuApi.Beatmap(score.BeatmapId, modRequestNumber, input.Gamemode).Result[0];

                    ppData pp = new PerformanceCalculator(score, beatmap, input.Gamemode).Calculate();
                    string achievedPp;

                    if (score.Rank.Equals("F") || beatmap.Approved == 4)
                    {
                        achievedPp = $"~~{Math.Round(score.PP > 0 && !input.IsDeltaT ? score.PP : pp.AchievedPp)}pp~~";
                    }
                    else
                    {
                        achievedPp = Math.Round(score.PP > 0 && !input.IsDeltaT ? score.PP : pp.AchievedPp).ToString() + "pp";
                    }

                    Dictionary <string, string> data = GetModeData(score, beatmap);

                    embed.AddField($"**{beatmap.Artist} - {beatmap.Title} [{beatmap.Version}]**",
                                   $"{GetRankEmoji(score)}{OsuHelper.ParseMods(score.EnabledMods)} {data["accuracy"]} {achievedPp}\n" +
                                   $"{data["combo"]} ({data["hits"]})");
                }
                else
                {
                    break;
                }
            }

            return(embed);
        }
        public ServerBeatmapDb(OsuApi api, string serverDir, bool reload = false)
        {
            this.api = api;
            folder   = serverDir;
            string db = Path.Combine(serverDir, "beatmaps.db");

            if (File.Exists(db))
            {
                hashes = JsonConvert.DeserializeObject <Dictionary <string, string> >(File.ReadAllText(db));
                Logger.LogAbsolute(Logging.BeatmapsDbSize, hashes.Count);
            }
            else
            {
                hashes = new Dictionary <string, string>();
            }
            if (reload)
            {
                foreach (var file in Directory.EnumerateFiles(Path.Combine(serverDir, "beatmaps")))
                {
                    hashes[Beatmap.MD5FromFile(file)] = Path.GetFileNameWithoutExtension(file);
                }
            }
        }
Exemple #22
0
        static void Main(string[] args)
        {
            Console.WriteLine("Collection Generator");
            Console.WriteLine("====================");
            Console.WriteLine("WARNING: ALL paths are hardcoded, meaning if you don't change them and recompile this program IT WILL NOT WORK."); //technically it could but eh, better safe than sorry.
            Console.WriteLine("If you did recompile it with your correct paths then you may continue... (Press enter)");
            Console.WriteLine("====================");

            Console.ReadLine();
            Console.WriteLine("Enter your osu!api key: ");

            string apiKey = Console.ReadLine();

            _api = new OsuApi(apiKey);

            //grab all maps from 2007
            Console.WriteLine("Getting beatmaps. This can take around 5 minutes.");
            var maps = GetBeatmapsFromYear(2007, false);

            Console.WriteLine("Generating collections");
            OsuFileIo.CollectionLoader.SaveOsdbCollection(GenByYear(maps), @"D:\Kod\kolekcje\ByYear.osdb");
            OsuFileIo.CollectionLoader.SaveOsdbCollection(GenByGenreV2(maps), @"D:\Kod\kolekcje\ByGenre.osdb");
            OsuFileIo.CollectionLoader.SaveOsdbCollection(GenBulkCollection(maps), @"D:\Kod\kolekcje\Bulk.osdb");
        }
Exemple #23
0
        public override object CommandHandler(SocketMessage socketMessage, string input, CommandArguments arguments)
        {
            ApplyMode(arguments);
            ApplyPlayer(socketMessage.Author.Id, input);

            //List<OsuUser> users = APIHelper<List<OsuUser>>.GetData(apiUrl + "get_user?u&k="+apiKey+"&u=" + username);
            if (_osuUser == null)
            {
                return("No user has been found.");
            }
            else
            {
                EmbedFieldBuilder topplayField = new EmbedFieldBuilder
                {
                    Name     = "Top plays",
                    Value    = "No top plays available",
                    IsInline = false
                };

                List <OsuPlay> topPlays = OsuApi.GetUserBest(_osuUser, _osuMode, 3, true);
                if (topPlays != null && topPlays.Count > 0)
                {
                    string topPlayString = "";
                    int    i             = 0;
                    topPlays.ForEach(play =>
                    {
                        i++;
                        string stringified = "**" + i + ". " + "[" + play.Beatmap.Title + " \\[" + play.Beatmap.DifficultyName +
                                             "\\]](https://osu.ppy.sh/beatmaps/" + play.Beatmap.BeatmapID + ") +" +
                                             ("" + ((OsuModsShort)play.Mods).ModParser() + "").Replace(", ", "") + "** (" +
                                             Mathf.Round(play.Beatmap.Starrating ?? 0, 1) + "\\*)\n" +
                                             OsuRanks.GetEmojiFromRank(play.Rank).ToString() + " • **" +
                                             Mathf.Round(play.Performance.CurrentValue).FormatNumber() + "pp** • " + Mathf.Round(play.Accuracy, 2) + "% • " +
                                             play.MaxCombo + (play.Beatmap.MaxCombo != null?"/" + play.Beatmap.MaxCombo:"x") + (play.IsFullcombo == "1" ? " FC" : "") + " • " +
                                             play.Score.FormatNumber() + "\n" +
                                             "Achieved " + DateTime.Parse(play.DateAchieved).Humanize();
                        topPlayString += stringified + "\n";
                    });
                    topplayField.Value = topPlayString;
                }

                EmbedBuilder embed = new EmbedBuilder()
                {
                    Color        = ParentManager.bot.BotColor,
                    Title        = "Profile of " + _osuUser.Name,
                    ThumbnailUrl = "https://a.ppy.sh/" + _osuUser.ID,
                    Description  = "Showing osu!" + _osuMode + " statistics",
                    Fields       = new List <EmbedFieldBuilder>()
                    {
                        new EmbedFieldBuilder()
                        {
                            Name  = "Rank",
                            Value =
                                _osuUser.Performance == 0
                                    ? "No PP or inactive"
                                    : ("#" + _osuUser.Globalrank.FormatNumber() + " (:flag_" + _osuUser.CountryCode.ToLower() +
                                       ": #" + _osuUser.Countryrank.FormatNumber() + ")"),
                        },
                        new EmbedFieldBuilder()
                        {
                            Name     = "Performance",
                            Value    = Mathf.Round(_osuUser.Performance).FormatNumber() + "pp",
                            IsInline = true
                        },
                        new EmbedFieldBuilder()
                        {
                            Name  = "Level",
                            Value = Mathf.Floor(_osuUser.Level) + " (" +
                                    Mathf.Round((Mathf.Round(_osuUser.Level, 2) - Mathf.Floor(_osuUser.Level)) * 100) +
                                    "% to level " + (Mathf.Ceil(_osuUser.Level)) + ")",
                            IsInline = true
                        },
                        new EmbedFieldBuilder()
                        {
                            Name     = "Ranked Score",
                            Value    = _osuUser.RankedScore.FormatNumber(),
                            IsInline = true
                        },
                        new EmbedFieldBuilder()
                        {
                            Name     = "Playtime",
                            Value    = TimeSpan.FromSeconds(_osuUser.Playtime).Humanize(maxUnit: TimeUnit.Hour),
                            IsInline = true
                        },
                        new EmbedFieldBuilder()
                        {
                            Name     = "Maps played",
                            Value    = _osuUser.Playcount.FormatNumber(),
                            IsInline = true
                        },
                        new EmbedFieldBuilder()
                        {
                            Name     = "Total Score",
                            Value    = _osuUser.TotalScore.FormatNumber(),
                            IsInline = true
                        },
                        new EmbedFieldBuilder()
                        {
                            Name  = "Ranks",
                            Value = OsuRanks.GetEmojiFromRank("X") + " " + _osuUser.GetCountRankSS().FormatNumber() + " " +
                                    "• " + OsuRanks.GetEmojiFromRank("S") + " " + _osuUser.GetCountRankS().FormatNumber() + " " +
                                    "• " + OsuRanks.GetEmojiFromRank("A") + " " + _osuUser.GetCountRankA().FormatNumber(),
                            IsInline = false
                        },
                        topplayField
                    },
                    Footer = new EmbedFooterBuilder()
                    {
                        Text = "User registered " + DateTime.Parse(_osuUser.Joindate).Humanize()
                    }
                };

                return(embed);
            }
        }
        private async Task ParseInfoAsync(
            HttpApiClient api,
            Endpoint sendBackEndpoint,
            GroupRequest r,
            int?osuId = null,
            TrustedUserInfo userInfo = default)
        {
            long   userId  = r.UserId;
            string comment = r.Comment;
            var    hints   = new List <Message>();

            if (!string.IsNullOrEmpty(comment))
            {
                var userNames = OsuHelper.DiscoverUsernames(comment).Where(n => !string.Equals(n, "osu", StringComparison.OrdinalIgnoreCase));
                if (osuId != null)
                {
                    bool success = userInfo != null; // 由于当前未从调用方法处获得上级 API 是否调用成功,在信息不为 null 时默认成功。
                    if (userInfo == null)
                    {                                // 可能的重试。
                        (success, userInfo) = await OsuApi.GetUserInfoAsync(osuId.Value, Mode.Standard).ConfigureAwait(false);
                    }
                    _ = await ProcessApplicantReportAsync(hints, null, (success, userInfo)).ConfigureAwait(false);

                    if (userInfo != null && !userNames.Any(n => string.Equals(userInfo.Name, n, StringComparison.OrdinalIgnoreCase)))
                    {// 绑定不一致
                        hints.Add(new Message("警告:其绑定的账号与申请不符。"));
                    }
                }
                else
                {// 忽略已绑定的情况,因为可能绑定不一致或者查询失败。
                    foreach (var name in userNames)
                    {
                        var userTuple = await OsuApi.GetUserInfoAsync(name, Bleatingsheep.Osu.Mode.Standard);

                        //// 我想用 8.0 新语法
                        //hints.Add(new Message($"{info?.Name ?? name}: " +
                        //    $"{(success ? info == null ? "不存在此用户。" : $"PP: {info.Performance}, PC: {info.PlayCount}, TTH: {info.TotalHits}" : "查询失败。")}"));

                        var info = await ProcessApplicantReportAsync(hints, name, userTuple).ConfigureAwait(false);

                        if (info == null)
                        {// 属于没有查到的情况(因为网络问题或者用户不存在),并且之前已经给出错误信息。
                            continue;
                        }

                        // 自动绑定,在请求消息完全匹配 osu! 用户名的前提下。
                        if (userNames.Count() == 1 &&
                            comment.TrimEnd().EndsWith($"答案:{name}", StringComparison.Ordinal) &&
                            info != null)
                        {
                            var bindingResult = await Database.AddNewBindAsync(
                                qq : r.UserId,
                                osuId : info.Id,
                                osuName : info.Name,
                                source : "Auto (Request)",
                                operatorId : r.UserId,
                                operatorName : info.Name).ConfigureAwait(false);

                            if (bindingResult.Success)
                            {
                                hints.Add(new Message($"自动绑定为 {info.Name}"));
                                goto binding_end;
                            }
                            else
                            {
                                hints.Add(new Message($"自动绑定失败。"));
                            }
                        }
                        // 提供绑定并放行的捷径。
                        if (info?.Performance < 2500)
                        {
                            var ms = new MemoryStream();
                            using (var bw = new BinaryWriter(ms, Encoding.UTF8, true))
                            {
                                bw.Write(userId);
                                bw.Write(info.Id);
                                bw.Write(r.Flag);
                            }
#pragma warning disable CA5351 // 不要使用损坏的加密算法
                            using var md5 = MD5.Create();
#pragma warning restore CA5351 // 不要使用损坏的加密算法
                            ms.Write(md5.ComputeHash(ms.ToArray()));
                            var bytes  = ms.ToArray();
                            var base64 = Convert.ToBase64String(bytes);
                            await api.SendMessageAsync(sendBackEndpoint, $"(占位)绑定为 {info.Name} 并放行:#{base64}#");
                        }
                        binding_end :;
                    }
                }
            }
            if (hints.Count > 0)
            {
                var newLine = new Message("\r\n");
                await api.SendMessageAsync(sendBackEndpoint, hints.Aggregate((m1, m2) =>
                {
                    return((m1.Sections.LastOrDefault()?.Type, m2.Sections.FirstOrDefault()?.Type) switch
                    {
                        ("text", "text") => m1 + newLine + m2,
                        _ => m1 + m2,
                    });
                })).ConfigureAwait(false);
Exemple #25
0
        public async Task <DiscordEmbedBuilder> CreateScoreEmbed()
        {
            int requestnumber = OsuHelper.GetModRequestNumber(score.EnabledMods);

            Task <UserData>      userRequest        = OsuApi.User(input);
            Task <BeatmapData[]> beatmapRequest     = OsuApi.Beatmap(score.BeatmapId ?? input.BeatmapId, requestnumber, input.Gamemode);
            Task <ScoreData[]>   leaderboardRequest = OsuApi.Leaderboard(score.BeatmapId, input.Gamemode);

            Task.WhenAll(
                userRequest,
                beatmapRequest,
                leaderboardRequest
                ).Wait();

            user        = userRequest.Result;
            beatmap     = beatmapRequest.Result[0];
            leaderboard = leaderboardRequest.Result;

            DiscordEmbedBuilder         embed = CreateBaseEmbed();
            Dictionary <string, string> data  = GetModeData(score, beatmap);
            string emoji = GetRankEmoji(score);
            string mods  = OsuHelper.ParseMods(score.EnabledMods);

            ppData pp = new PerformanceCalculator(score, beatmap, input.Gamemode).Calculate();
            string achievedPp;

            if (score.Rank.Equals("F") || beatmap.Approved == 4)
            {
                achievedPp = $"~~{Math.Round(score.PP > 0 && !input.IsDeltaT ? score.PP : pp.AchievedPp)}pp~~";
            }
            else
            {
                achievedPp = Math.Round(score.PP > 0 && !input.IsDeltaT ? score.PP : pp.AchievedPp).ToString() + "pp";
            }

            var    totalTimeSpan = TimeSpan.FromSeconds(beatmap.TotalLength);
            var    hitTimeSpan   = TimeSpan.FromSeconds(beatmap.HitLength);
            string totalLength   = string.Format("{0:D2}:{1:D2}", totalTimeSpan.Minutes, totalTimeSpan.Seconds);
            string hitLength     = string.Format("{0:D2}:{1:D2}", hitTimeSpan.Minutes, hitTimeSpan.Seconds);

            int retryCount = GetRetryCount();

            if (retryCount > 0)
            {
                embed.Author.Name += $" | Try #{retryCount}";
            }

            embed.WithDescription($"[{beatmap.Artist} - {beatmap.Title} [{beatmap.Version}]](https://osu.ppy.sh/b/{beatmap.BeatmapId})\n" +
                                  $"{mods} **{achievedPp}**");

            int leaderboardPosition = GetLeaderboardPosition();

            if (leaderboardPosition > 0)
            {
                embed.Description += $" BM#{leaderboardPosition}";
            }

            embed.AddField("**Score**",
                           $"{emoji} {score.Score.ToString("#,##0")}",
                           true);

            embed.AddField("**Combo**",
                           data["combo"],
                           true);

            embed.AddField("**Accuracy**",
                           data["accuracy"],
                           true);

            embed.AddField("**Hits**",
                           data["hits"],
                           true);

            if (pp.FullComboPp != 0)
            {
                embed.AddField("**PP if FC**",
                               Math.Round(pp.FullComboPp) + "pp",
                               true);
            }

            if (pp.ssPp != 0)
            {
                embed.AddField("**PP if SS**",
                               Math.Round(pp.ssPp) + "pp",
                               true);
            }

            embed.AddField("**Beatmap Values**",
                           $"★{Math.Round(beatmap.DifficultyRating, 2)} **Length**: {totalLength} ({hitLength}) **BPM** {beatmap.bpm}\n" +
                           data["stats"]);

            embed.WithFooter($"Beatmap by: {beatmap.Creator} | Played on {score.Date}");

            Database.SetLastMap(input.DiscordChannelId, beatmap.BeatmapId);
            return(embed);
        }
Exemple #26
0
 public BeatmapData(string apiKey, IMapDataManager mapCacher)
 {
     _mapCacher = mapCacher;
     _osuApi    = new OsuApi(apiKey);
 }
        public async Task ProcessAsync(MessageContext context, HttpApiClient api)
        {
            var uid = await EnsureGetBindingIdAsync(context.UserId).ConfigureAwait(false);

            var apiTask = OsuApi.GetUserInfoAsync(uid, Bleatingsheep.Osu.Mode.Standard).ConfigureAwait(false);

            using (var page = await Chrome.OpenNewPageAsync().ConfigureAwait(false))
            {
                await page.SetViewportAsync(new ViewPortOptions
                {
                    DeviceScaleFactor = 2.75,
                    Width             = 1440,
                    Height            = 900,
                }).ConfigureAwait(false);

                await page.GoToAsync($"https://osu.ppy.sh/users/{uid}/osu").ConfigureAwait(false);

                // wait for load complete
                const string waitSelector = @"body > div.osu-layout__section.osu-layout__section--full.js-content.community_profile > div > div > div > div.osu-layout__section.osu-layout__section--users-extra > div > div > div > div:nth-child(2)";
                await page.WaitForSelectorAsync(waitSelector).ConfigureAwait(false);

                const string bestSelector = "body > div.osu-layout__section.osu-layout__section--full.js-content.community_profile > div > div > div > div.osu-layout__section.osu-layout__section--users-extra > div > div > div > div:nth-child(2) > div > div.play-detail-list";
                //ElementHandle bpsElement = await page.QuerySelectorAsync(bestSelector).ConfigureAwait(false);

                const string  buttonSelector = "body > div.osu-layout__section.osu-layout__section--full.js-content.community_profile > div > div > div > div.osu-layout__section.osu-layout__section--users-extra > div > div > div > div:nth-child(2) > div > div.profile-extra-entries__item > button";
                ElementHandle button         = await page.QuerySelectorAsync(buttonSelector).ConfigureAwait(false);

                ElementHandle[]? bpList = default;
                int maxTryTimes = 4;
                while (button != null && maxTryTimes-- != 0)
                {
                    //check bp counts.

                    bpList = await page.QuerySelectorAllAsync(bestSelector + " > div").ConfigureAwait(false);

                    await button.ClickAsync().ConfigureAwait(false);

                    // wait for click complete
                    await page.WaitForSelectorAsync(bestSelector + $" > div:nth-child({bpList.Length})",
                                                    new WaitForSelectorOptions { Timeout = 8000 /*ms*/ }).ConfigureAwait(false);

                    // seems that bp div adding and button availability changing is NOT synchronized
                    // wait for button availability change
                    await page.WaitForTimeoutAsync(500).ConfigureAwait(false);

                    // requery button
                    button = await page.QuerySelectorAsync(buttonSelector).ConfigureAwait(false);
                }

                if (bpList == null)
                {
                    await api.SendMessageAsync(context.Endpoint, "查询失败。").ConfigureAwait(false);

                    return;
                }

                // filter

                /*
                 * bpList = document.querySelectorAll("body > div.osu-layout__section.osu-layout__section--full.js-content.community_profile > div > div > div > div.osu-layout__section.osu-layout__section--users-extra > div > div > div > div:nth-child(2) > div > div.play-detail-list > div");
                 *
                 * bpList.forEach((element) => { var dateTime = element.querySelector("div.play-detail__group.play-detail__group--top > div.play-detail__detail > div > span.play-detail__time > time").getAttribute("datetime"); if (new Date() - Date.parse(dateTime) > 86400000) element.remove();  })
                 */

                await page.EvaluateExpressionAsync(@"bpList = document.querySelectorAll(""body > div.osu-layout__section.osu-layout__section--full.js-content.community_profile > div > div > div > div.osu-layout__section.osu-layout__section--users-extra > div > div > div > div:nth-child(2) > div > div.play-detail-list > div"");").ConfigureAwait(false);

                await page.EvaluateExpressionAsync(@"bpList.forEach((element) => { var dateTime = element.querySelector(""div.play-detail__group.play-detail__group--top > div.play-detail__detail > div > span.play-detail__time > time"").getAttribute(""datetime""); if (new Date() - Date.parse(dateTime) > 86400000) element.remove();  })").ConfigureAwait(false);

                // check
                bpList = await page.QuerySelectorAllAsync(bestSelector + " > div").ConfigureAwait(false);

                if (bpList.Length == 0)
                {
                    await api.SendMessageAsync(context.Endpoint, "最近 24 小时没有更新 bp。").ConfigureAwait(false);

                    return;
                }

                //screenshot
                //delete pinned elements
                await(await page.QuerySelectorAsync("body > div.js-pinned-header.hidden-xs.no-print.nav2-header > div.nav2-header__body").ConfigureAwait(false)).EvaluateFunctionAsync(@"(element) => element.remove()").ConfigureAwait(false);
                await(await page.QuerySelectorAsync("body > div.osu-layout__section.osu-layout__section--full.js-content.community_profile > div > div > div > div.hidden-xs.page-extra-tabs.page-extra-tabs--profile-page.js-switchable-mode-page--scrollspy-offset").ConfigureAwait(false)).EvaluateFunctionAsync(@"(element) => element.remove()").ConfigureAwait(false);

                // add extra information
                await page.EvaluateExpressionAsync($@"document.querySelector(""{bestSelector}"").parentElement.parentElement.querySelector(""h3"").textContent += "" (用户名:"" + {JsonConvert.SerializeObject((await apiTask).Item2?.Name ?? "获取失败")} + "" 查询时间:"" + {JsonConvert.SerializeObject(DateTime.Now.ToString("yyyy-MM-dd H:mm)"))}").ConfigureAwait(false);

                //ElementHandle printElement = await page.QuerySelectorAsync(bestSelector).ConfigureAwait(false);
                var printElement =
                    await(await page.QuerySelectorAsync(bestSelector).ConfigureAwait(false))
                    .EvaluateFunctionHandleAsync("(element) => element.parentNode.parentNode").ConfigureAwait(false) as ElementHandle;
                printElement ??= await page.QuerySelectorAsync(bestSelector).ConfigureAwait(false);

                var data = await printElement.ScreenshotDataAsync(new ScreenshotOptions()).ConfigureAwait(false);

                await api.SendMessageAsync(context.Endpoint, Message.ByteArrayImage(data)).ConfigureAwait(false);
            }
        }
Exemple #28
0
 public OsuModule(OsuApi api)
 {
     _api = api;
 }
Exemple #29
0
 public OsuUser FindUser(string query)
 {
     return(OsuApi.GetUser(query));
 }
Exemple #30
0
        public MatchCost(string matchLink, int warmupCount)
        {
            match            = OsuApi.Match(matchLink.Substring(37)).Result;
            this.warmupCount = warmupCount;

            if (match.Games.Length == 0)
            {
                throw new Exception("jij bent echt kankerdom");
            }

            foreach (MultiPlayerGame game in match.Games)
            {
                if (warmupCount != 0)
                {
                    warmupCount--;
                    continue;
                }

                foreach (MultiPlayerScore score in game.Scores)
                {
                    if (score.Score < 5000)
                    {
                        continue;
                    }

                    if (score.Team == 0)
                    {
                        isFfa = true;

                        if (!totalScores.ContainsKey(score.UserId))
                        {
                            totalScores.Add(score.UserId, new List <double>());
                        }

                        totalScores[score.UserId].Add(score.Score);
                    }
                    else if (score.Team == 1)
                    {
                        blueTotal += score.Score;

                        if (!blueScores.ContainsKey(score.UserId))
                        {
                            blueScores.Add(score.UserId, new List <double>());
                        }

                        blueScores[score.UserId].Add(score.Score);
                        blueScoreCount++;
                    }
                    else if (score.Team == 2)
                    {
                        redTotal += score.Score;

                        if (!redScores.ContainsKey(score.UserId))
                        {
                            redScores.Add(score.UserId, new List <double>());
                        }

                        redScores[score.UserId].Add(score.Score);
                        redScoreCount++;
                    }

                    total += score.Score;
                    totalScoreCount++;
                }

                mapCount++;
            }

            totalAverage = total / totalScoreCount;
            blueAverage  = blueTotal / blueScoreCount;
            redAverage   = redTotal / redScoreCount;

            if (isFfa)
            {
                foreach (KeyValuePair <int, List <double> > playerScores in totalScores)
                {
                    double cost = 0;

                    foreach (int score in playerScores.Value)
                    {
                        cost += score / totalAverage;
                    }

                    totalCosts.Add(playerScores.Key, new double[] {
                        cost / playerScores.Value.Count * Math.Pow(1.2, Math.Pow(playerScores.Value.Count / mapCount, 0.4))
                    });
                }
            }
            else
            {
                foreach (KeyValuePair <int, List <double> > playerScores in blueScores)
                {
                    double cost     = 0;
                    double teamcost = 0;

                    foreach (int score in playerScores.Value)
                    {
                        cost     += score / totalAverage;
                        teamcost += score / blueAverage;
                    }

                    blueCosts.Add(playerScores.Key, new double[] {
                        cost / playerScores.Value.Count * Math.Pow(1.2, Math.Pow(playerScores.Value.Count / mapCount, 0.4)),
                        teamcost / playerScores.Value.Count * Math.Pow(1.2, Math.Pow(playerScores.Value.Count / mapCount, 0.4))
                    });
                }

                foreach (KeyValuePair <int, List <double> > playerScores in redScores)
                {
                    double cost     = 0;
                    double teamcost = 0;

                    foreach (int score in playerScores.Value)
                    {
                        cost     += score / totalAverage;
                        teamcost += score / redAverage;
                    }

                    redCosts.Add(playerScores.Key, new double[] {
                        cost / playerScores.Value.Count * Math.Pow(1.2, Math.Pow(playerScores.Value.Count / mapCount, 0.4)),
                        teamcost / playerScores.Value.Count * Math.Pow(1.2, Math.Pow(playerScores.Value.Count / mapCount, 0.4))
                    });
                }
            }
        }