Esempio n. 1
0
        private async Task OnTrackIssue(LavaPlayer ply, ILavaTrack lavaTrack, string error = null)
        {
            if (error != null)
            {
                this.Logger.Nice("MusicPlayer", ConsoleColor.Red, $"Exception thrown by lavalink for track <{lavaTrack.Title}>\n{error}");
                if (lavaTrack.Uri.AbsoluteUri.Contains("soundcloud.com"))
                {
                    error = $"{error} It is likely that this track is not usable outside of SoundCloud.";
                }
            }
            else
            {
                this.Logger.Nice("MusicPlayer", ConsoleColor.Red, $"Track <{lavaTrack.Title}> got stuck");
                error = "The track got stuck.";
            }

            EmbedBuilder builder = new EmbedBuilder();

            builder
            .WithColorType(EmbedColorType.Warning)
            .WithFooter("music player")
            .WithDescription("🎶 Could not play track:")
            .WithField("Url", $"**{lavaTrack.Uri}**")
            .WithField("Error", error);

            await this.MessageSender.SendAsync(ply.TextChannel, builder.Build());
        }
Esempio n. 2
0
        private Embed BuildTrackEmbed(ILavaTrack track, int volume, bool paused, bool looping)
        {
            EmbedBuilder builder = new EmbedBuilder();

            builder
            .WithLimitedTitle(track.Title)
            .WithField("Author", track.Author)
            .WithField("Stream", track.IsStream)
            .WithField("Volume", $"{volume}%")
            .WithField("Paused", paused)
            .WithField("Looping", looping)
            .WithFooter("music player");

            string url = track.Uri.AbsoluteUri;

            if (url.Length < 1000)
            {
                builder.WithDescription($"🎶 Now playing the **[following track]({url})**");
            }
            else
            {
                builder.WithDescription("🎶 Now playing the following track");
            }

            builder.WithField("Length", this.FormattedTrack(track), false);

            return(builder.Build());
        }
Esempio n. 3
0
        private async Task <(bool, YoutubeVideo)> TryGetVideoAsync(ILavaTrack lavaTrack)
        {
            bool         failed = false;
            YoutubeVideo video  = null;

            if (lavaTrack.Uri.AbsoluteUri.Contains("youtu"))
            {
                Match match = YtRegex.Match(lavaTrack.Uri.AbsoluteUri);
                if (!match.Success)
                {
                    failed = true;
                }

                video = await this.FetchYtRelatedVideoAsync(match.Value);

                if (video == null)
                {
                    failed = true;
                }
            }
            else
            {
                failed = true;
            }

            return(failed, video);
        }
Esempio n. 4
0
        /// <summary>
        /// Fetches thumbnail of the specified track.
        /// </summary>
        /// <param name="track"><see cref="ILavaTrack"/></param>
        public static async Task <string> FetchThumbnailAsync(this ILavaTrack track)
        {
            var url = string.Empty;

            switch ($"{track.Uri}".ToLower())
            {
            case var yt when yt.Contains("youtube"):
                return($"https://img.youtube.com/vi/{track.Id}/maxresdefault.jpg");

            case var twich when twich.Contains("twitch"):
                url = $"https://api.twitch.tv/v4/oembed?url={track.Uri}";

                break;

            case var sc when sc.Contains("soundcloud"):
                url = $"https://soundcloud.com/oembed?url={track.Uri}&format=json";

                break;

            case var vim when vim.Contains("vimeo"):
                url = $"https://vimeo.com/api/oembed.json?url={track.Uri}";

                break;
            }

            var req = await HttpHelper.Instance.GetStringAsync(url);

            var parse = JObject.Parse(req);

            return(!parse.TryGetValue("thumbnail_url", out var thumb)
                ? "https://i.imgur.com/YPCEUDK.gif"
                : $"{thumb}");
        }
Esempio n. 5
0
        private async Task <Embed> GetNewTrackEmbed(ILavaTrack lavaTrack, IMessage msg = null)
        {
            string thumbnailUrl = await GetThumbnailAsync(lavaTrack);

            EmbedBuilder builder = new EmbedBuilder();

            if (msg != null)
            {
                builder.WithAuthorNickname(msg);
            }
            const string desc = "🎶 Added the following track to the queue:";

            if (!string.IsNullOrWhiteSpace(thumbnailUrl))
            {
                builder.WithThumbnailUrl(thumbnailUrl);
            }
            return(builder
                   .WithDescription(desc)
                   .WithFooter("music player")
                   .WithField("Title", lavaTrack.Title)
                   .WithField("Author", lavaTrack.Author)
                   .WithField("Length", lavaTrack.IsStream ? " - " : lavaTrack.Length.ToString(@"hh\:mm\:ss"))
                   .WithField("Stream", lavaTrack.IsStream)
                   .Build());
        }
Esempio n. 6
0
        private string FormattedTrack(ILavaTrack track)
        {
            string len, pos, line;

            if (!track.HasLength)
            {
                len  = TimeSpan.Zero.ToString(@"hh\:mm\:ss");
                pos  = len;
                line = new string('─', 20) + "⚪";
            }
            else
            {
                len = track.Length.ToString(@"hh\:mm\:ss");
                pos = track.Position.ToString(@"hh\:mm\:ss");
                double perc      = (double)track.Position.Ticks / track.Length.Ticks * 100.0;
                int    circlepos = Math.Clamp((int)Math.Ceiling(21.0 / 100.0 * perc), 0, 21); //Make sure its clamped
                if (circlepos > 0)
                {
                    line = new string('─', circlepos - 1) + "⚪" + new string('─', 21 - circlepos);
                }
                else
                {
                    line = "⚪" + new string('─', 20);
                }
            }

            return($"```http\n▶ {line} {pos} / {len}\n```");
        }
Esempio n. 7
0
 private static async Task <string> GetThumbnailAsync(ILavaTrack track)
 {
     try
     {
         return(await track.FetchThumbnailAsync());
     }
     catch
     {
         return(string.Empty);
     }
 }
Esempio n. 8
0
        private static async Task <string> GetTrackHash(ILavaTrack track)
        {
            string trackHash = track.Hash;

            if (track is IAsyncLazyLoadTrack async)
            {
                trackHash = (await async.GetInnerTrackAsync()).Hash;
            }

            return(trackHash);
        }
Esempio n. 9
0
        public async Task <ILavaTrack> GetInnerTrackAsync()
        {
            if (this.InnerTrack != null)
            {
                return(this.InnerTrack);
            }

            ILavaTrack track = await this.InnerTrackCallback();

            this.InnerTrack = track;
            return(track);
        }
Esempio n. 10
0
        public RadioTrack(ILavaTrack innerTrack)
        {
            this.Genre      = "unknown";
            this.InnerTrack = innerTrack;

            foreach ((string key, string value) in StaticData.Instance.RadioSources)
            {
                if (value.Equals(innerTrack.Uri.AbsoluteUri))
                {
                    this.Genre = key;
                }
            }
        }
Esempio n. 11
0
        public async Task <List <IUserMessage> > AddPlaylistAsync(IVoiceChannel vc, ITextChannel chan, string name, IEnumerable <ILavaTrack> trs)
        {
            IEnergizePlayer ply = await this.ConnectAsync(vc, chan);

            if (ply == null)
            {
                return(null);
            }

            List <ILavaTrack> tracks = trs.ToList();

            if (tracks.Count < 1)
            {
                return(new List <IUserMessage>
                {
                    await this.MessageSender.SendWarningAsync(chan, "music player", "The loaded playlist does not contain any tracks")
                });
            }

            if (ply.IsPlaying)
            {
                foreach (ILavaTrack track in tracks)
                {
                    ply.Queue.Enqueue(track);
                }

                return(new List <IUserMessage>
                {
                    await this.MessageSender.SendGoodAsync(chan, "music player", $"🎶 Added `{tracks.Count}` tracks from `{name}`")
                });
            }
            ILavaTrack lavaTrack = tracks[0];

            tracks.RemoveAt(0);

            if (tracks.Count > 0)
            {
                foreach (ILavaTrack tr in tracks)
                {
                    ply.Queue.Enqueue(tr);
                }
            }

            await ply.Lavalink.PlayAsync(lavaTrack);

            return(new List <IUserMessage>
            {
                await this.MessageSender.SendGoodAsync(chan, "music player", $"🎶 Added `{tracks.Count}` tracks from `{name}`"),
                await this.SendPlayerAsync(ply, lavaTrack, chan)
            });
        }
Esempio n. 12
0
        private static async Task OnPlayReactionAsync(PaginatorSenderService sender, Paginator <object> paginator, Cacheable <IUserMessage, ulong> cache, ISocketMessageChannel chan, SocketReaction reaction)
        {
            if (!(chan is IGuildChannel) || reaction.User.Value == null)
            {
                return;
            }
            IGuildUser guser = (IGuildUser)reaction.User.Value;

            if (guser.VoiceChannel == null)
            {
                return;
            }

            ITextChannel        textChan = (ITextChannel)chan;
            IMusicPlayerService music    = sender.ServiceManager.GetService <IMusicPlayerService>("Music");

            switch (paginator.CurrentValue)
            {
            case ILavaTrack track:
                await music.AddTrackAsync(guser.VoiceChannel, textChan, track);

                await chan.DeleteMessageAsync(paginator.Message);

                break;

            case string url:
                if (string.IsNullOrWhiteSpace(url))
                {
                    return;
                }

                SearchResult result = await music.LavaRestClient.SearchTracksAsync(url);

                List <ILavaTrack> tracks = result.Tracks.ToList();
                if (tracks.Count > 0)
                {
                    ILavaTrack tr = tracks[0];
                    await music.AddTrackAsync(guser.VoiceChannel, textChan, tr);

                    await chan.DeleteMessageAsync(paginator.Message);
                }
                else
                {
                    await sender.MessageSender.SendWarningAsync(chan, "music player", $"Could not add the following Url to the queue\n{url}");
                }

                break;
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Plays the specified <paramref name="track"/>.
        /// </summary>
        /// <param name="track"><see cref="ILavaTrack"/></param>
        /// <param name="noReplace">If set to true, this operation will be ignored if a track is already playing or paused.</param>
        public async Task PlayAsync(ILavaTrack track, bool noReplace = false)
        {
            this.IsPlaying    = true;
            this.CurrentTrack = track;
            this.LastUpdate   = DateTimeOffset.Now;
            if (!noReplace)
            {
                Volatile.Write(ref this._isPaused, false);
            }
            string trackHash = await GetTrackHash(track);

            var payload = new PlayPayload(this.VoiceChannel.GuildId, trackHash, noReplace);

            await this._socketHelper.SendPayloadAsync(payload);
        }
Esempio n. 14
0
        /*private async Task OnSocketClosed(int errorCode, string reason, bool byRemote)
         * {
         *  await this.DisconnectAllPlayersAsync("Music streaming is unavailable at the moment, disconnecting");
         *  SocketChannel chan = this.DiscordClient.GetChannel(Config.Instance.Discord.BugReportChannelID);
         *  if (chan != null)
         *  {
         *      EmbedBuilder builder = new EmbedBuilder();
         *      builder
         *          .WithDescription("Lavalink lost connection to Discord websocket")
         *          .WithField("Error Code", errorCode)
         *          .WithField("Reason", reason)
         *          .WithField("By Remote", byRemote)
         *          .WithColorType(EmbedColorType.Warning)
         *          .WithFooter("lavalink error");
         *
         *      await this.MessageSender.SendAsync(chan, builder);
         *  }
         * }*/

        private async Task OnPlayerUpdated(LavaPlayer lply, ILavaTrack track, TimeSpan position)
        {
            if (this.Players.TryGetValue(lply.VoiceChannel.GuildId, out IEnergizePlayer ply))
            {
                if (ply.TrackPlayer != null)
                {
                    if (!track.IsStream && !ply.IsPaused)
                    {
                        await ply.TrackPlayer.Update(track, ply.Volume, ply.IsPaused, ply.IsLooping);
                    }

                    ply.Refresh();
                }
            }

            IGuild guild = lply.VoiceChannel.Guild;
            string msg   = $"Updated track <{track.Title}> ({position}) for player in guild <{guild.Name}>";

            this.Logger.LogTo("victoria.log", msg);
        }
Esempio n. 15
0
        private async Task OnTrackFinished(LavaPlayer lavalink, ILavaTrack lavaTrack, TrackEndReason reason)
        {
            if (!reason.ShouldPlayNext())
            {
                return;
            }

            IEnergizePlayer ply = this.Players[lavalink.VoiceChannel.GuildId];

            if (ply.IsLooping)
            {
                lavaTrack.ResetPosition();
                await ply.Lavalink.PlayAsync(lavaTrack);
            }
            else
            {
                if (ply.Queue.TryDequeue(out IQueueObject obj))
                {
                    if (obj is ILavaTrack newTrack)
                    {
                        await ply.Lavalink.PlayAsync(newTrack);

                        await this.SendPlayerAsync(ply, newTrack);
                    }
                }
                else
                {
                    if (ply.Autoplay && ply.Queue.Count == 0)
                    {
                        await this.AddRelatedYtContentAsync(ply.VoiceChannel, ply.TextChannel, lavaTrack);
                    }
                    else
                    {
                        if (ply.TrackPlayer != null)
                        {
                            await ply.TrackPlayer.DeleteMessage();
                        }
                    }
                }
            }
        }
Esempio n. 16
0
        public async Task SeekTrackAsync(IVoiceChannel vc, ITextChannel chan, int amount)
        {
            IEnergizePlayer ply = await this.ConnectAsync(vc, chan);

            if (ply == null)
            {
                return;
            }
            if (!ply.IsPlaying)
            {
                return;
            }

            ILavaTrack lavaTrack = ply.CurrentTrack;
            TimeSpan   total     = lavaTrack.Position.Add(TimeSpan.FromSeconds(amount));

            if (total < lavaTrack.Length && total >= TimeSpan.Zero)
            {
                await ply.Lavalink.SeekAsync(total);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Plays the specified <paramref name="track"/>.
        /// </summary>
        /// <param name="track"></param>
        /// <param name="startTime">Optional setting that determines the number of milliseconds to offset the track by.</param>
        /// <param name="stopTime">optional setting that determines at the number of milliseconds at which point the track should stop playing.</param>
        /// <param name="noReplace">If set to true, this operation will be ignored if a track is already playing or paused.</param>
        public async Task PlayAsync(ILavaTrack track, TimeSpan startTime, TimeSpan stopTime, bool noReplace = false)
        {
            if (startTime.TotalMilliseconds < 0 || stopTime.TotalMilliseconds < 0)
            {
                throw new InvalidOperationException("Start and stop must be greater than 0.");
            }

            if (startTime <= stopTime)
            {
                throw new InvalidOperationException("Stop time must be greater than start time.");
            }

            this.IsPlaying    = true;
            this.CurrentTrack = track;
            if (!noReplace)
            {
                Volatile.Write(ref this._isPaused, false);
            }
            string trackHash = await GetTrackHash(track);

            var payload = new PlayPayload(this.VoiceChannel.GuildId, trackHash, startTime, stopTime, noReplace);

            await this._socketHelper.SendPayloadAsync(payload);
        }
Esempio n. 18
0
        public async Task SkipTrackAsync(IVoiceChannel vc, ITextChannel chan)
        {
            IEnergizePlayer ply = await this.ConnectAsync(vc, chan);

            if (ply == null)
            {
                return;
            }

            if (ply.CurrentRadio != null)
            {
                ply.CurrentRadio = null;
            }

            if (!ply.IsPlaying)
            {
                return;
            }

            if (ply.Queue.Count > 0)
            {
                await ply.Lavalink.SkipAsync();

                await this.SendPlayerAsync(ply, ply.CurrentTrack);
            }
            else
            {
                ILavaTrack oldTrack = ply.CurrentTrack;
                await ply.Lavalink.StopAsync();

                if (ply.Autoplay)
                {
                    await this.AddRelatedYtContentAsync(vc, chan, oldTrack);
                }
            }
        }
Esempio n. 19
0
        public async Task <IUserMessage> PlayRadioAsync(IVoiceChannel vc, ITextChannel chan, ILavaTrack lavaTrack)
        {
            IEnergizePlayer ply = await this.ConnectAsync(vc, chan);

            if (ply == null)
            {
                return(null);
            }

            RadioTrack radio = new RadioTrack(lavaTrack);

            ply.Queue.Clear();
            ply.CurrentRadio = radio;
            await ply.Lavalink.PlayAsync(lavaTrack);

            return(await this.SendPlayerAsync(ply, radio, chan));
        }
Esempio n. 20
0
        private bool OnMessage(string message)
        {
            this.ShadowLog?.WriteLog(LogSeverity.Debug, message);
            JObject json = JObject.Parse(message);

            ulong      guildId = 0;
            LavaPlayer player;

            if (json.TryGetValue("guildId", out JToken guildToken))
            {
                guildId = ulong.Parse($"{guildToken}");
            }

            string opCode = $"{json.GetValue("op")}";

            switch (opCode)
            {
            case "playerUpdate":
                /*if (!this.Players.TryGetValue(guildId, out player))
                 *  return false;
                 *
                 * PlayerState state = json.GetValue("state").ToObject<PlayerState>();
                 * player.CurrentTrack.Position = state.Position;
                 * player.LastUpdate = state.Time;
                 *
                 * this.OnPlayerUpdated?.Invoke(player, player.CurrentTrack, state.Position);*/
                break;

            case "stats":
                this.ServerStats = json.ToObject <ServerStats>();
                this.OnServerStats?.Invoke(this.ServerStats);
                break;

            case "event":
                EventType evt = json.GetValue("type").ToObject <EventType>();
                if (!this.Players.TryGetValue(guildId, out player))
                {
                    return(false);
                }

                ILavaTrack track = default;
                if (json.TryGetValue("track", out JToken hash))
                {
                    track = TrackHelper.DecodeTrack($"{hash}");
                }

                switch (evt)
                {
                case EventType.TrackEnd:
                    TrackEndReason endReason = json.GetValue("reason").ToObject <TrackEndReason>();
                    if (endReason != TrackEndReason.Finished)
                    {
                        if (endReason != TrackEndReason.Replaced)
                        {
                            player.IsPlaying    = false;
                            player.CurrentTrack = default;
                        }

                        this.OnTrackFinished?.Invoke(player, track, endReason);
                    }

                    break;

                case EventType.TrackException:
                    string error = json.GetValue("error").ToObject <string>();
                    player.CurrentTrack = track;
                    this.OnTrackException?.Invoke(player, track, error);
                    break;

                case EventType.TrackStuck:
                    long timeout = json.GetValue("thresholdMs").ToObject <long>();
                    player.CurrentTrack = track;
                    this.OnTrackStuck?.Invoke(player, track, timeout);
                    break;

                case EventType.WebSocketClosed:
                    string reason   = json.GetValue("reason").ToObject <string>();
                    int    code     = json.GetValue("code").ToObject <int>();
                    bool   byRemote = json.GetValue("byRemote").ToObject <bool>();
                    this.OnSocketClosed?.Invoke(code, reason, byRemote);
                    break;

                default:
                    this.ShadowLog?.WriteLog(LogSeverity.Warning, $"Missing implementation of {evt} event.");
                    break;
                }

                break;

            default:
                this.ShadowLog?.WriteLog(LogSeverity.Warning, $"Missing handling of {opCode} OP code.");
                break;
            }

            return(true);
        }
Esempio n. 21
0
 /// <summary>
 /// Searches lyrics for the specified track.
 /// </summary>
 /// <param name="track"><see cref="ILavaTrack"/></param>
 public static Task <string> FetchLyricsAsync(this ILavaTrack track)
 {
     return(LyricsHelper.SearchAsync(track.Author, track.Title));
 }
Esempio n. 22
0
        public async Task <IUserMessage> SendNewTrackAsync(IMessage msg, ILavaTrack lavaTrack)
        {
            Embed embed = await this.GetNewTrackEmbed(lavaTrack, msg);

            return(await this.MessageSender.SendAsync(msg, embed));
        }
Esempio n. 23
0
        public async Task <IUserMessage> SendNewTrackAsync(ITextChannel chan, ILavaTrack lavaTrack)
        {
            Embed embed = await this.GetNewTrackEmbed(lavaTrack);

            return(await this.MessageSender.SendAsync(chan, embed));
        }
Esempio n. 24
0
        private async Task AddRelatedYtContentAsync(IVoiceChannel vc, ITextChannel chan, ILavaTrack oldTrack)
        {
            (bool failed, YoutubeVideo video) = await this.TryGetVideoAsync(oldTrack);

            string videoUrl = await this.GetNextTrackVideoUrlAsync(failed, video);

            SearchResult res = await this.LavaRestClient.SearchTracksAsync(videoUrl);

            List <ILavaTrack> tracks = res.Tracks.ToList();

            if (tracks.Count == 0)
            {
                return;
            }

            switch (res.LoadType)
            {
            case LoadType.SearchResult:
            case LoadType.TrackLoaded:
                await this.AddTrackAsync(vc, chan, tracks[0]);

                break;

            case LoadType.PlaylistLoaded:
                await this.AddPlaylistAsync(vc, chan, res.PlaylistInfo.Name, tracks);

                break;

            default:
                await this.MessageSender.SendWarningAsync(chan, "music player", "Failed to get/load the next autoplay track");

                break;
            }
        }
Esempio n. 25
0
        public async Task <IUserMessage> AddTrackAsync(IVoiceChannel vc, ITextChannel chan, ILavaTrack lavaTrack)
        {
            IEnergizePlayer ply = await this.ConnectAsync(vc, chan);

            if (ply == null)
            {
                return(null);
            }

            if (ply.IsPlaying)
            {
                ply.Queue.Enqueue(lavaTrack);
                return(await this.SendNewTrackAsync(chan, lavaTrack));
            }
            await ply.Lavalink.PlayAsync(lavaTrack);

            return(await this.SendPlayerAsync(ply, lavaTrack, chan));
        }
Esempio n. 26
0
 /// <summary>
 ///     Initialize SpotifyTrack with an already searched LavaTrack
 /// </summary>
 /// <param name="spotifyInfo">Spotify information from the Spotify API</param>
 /// <param name="innerTrack">Searched LavaTrack</param>
 public SpotifyTrack(SpotifyTrackInfo spotifyInfo, ILavaTrack innerTrack)
 {
     this.SpotifyInfo = spotifyInfo;
     this.InnerTrack  = innerTrack;
 }