diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index b182c76f..a918fc11 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -243,6 +243,31 @@ namespace NadekoBot.Modules.Music.Classes }); } + internal async Task UpdateSongDurationsAsync() + { + var curSong = CurrentSong; + var toUpdate = playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal && + s.TotalLength == TimeSpan.Zero); + if (curSong != null) + toUpdate = toUpdate.Append(curSong); + var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3)) + .Distinct(); + + var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids); + + toUpdate.ForEach(s => + { + foreach (var kvp in durations) + { + if (s.SongInfo.Query.EndsWith(kvp.Key)) + { + s.TotalLength = kvp.Value; + return; + } + } + }); + } + public void Destroy() { actionQueue.Enqueue(async () => diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index db2c72f8..6c8a694c 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -38,7 +38,14 @@ namespace NadekoBot.Modules.Music.Classes public string PrettyCurrentTime() { var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); - return $"【{(int)time.TotalMinutes}m {time.Seconds}s】"; + var str = $"【{(int)time.TotalMinutes}m {time.Seconds}s】**/** "; + if (TotalLength == TimeSpan.Zero) + str += "**?**"; + else if (TotalLength == TimeSpan.MaxValue) + str += "**∞**"; + else + str += $"【{(int)TotalLength.TotalMinutes}m {TotalLength.Seconds}s】"; + return str; } const int milliseconds = 20; @@ -60,6 +67,8 @@ namespace NadekoBot.Modules.Music.Classes } } + public TimeSpan TotalLength { get; set; } = TimeSpan.Zero; + public Song(SongInfo songInfo) { this.SongInfo = songInfo; @@ -263,7 +272,8 @@ namespace NadekoBot.Modules.Music.Classes Provider = "Radio Stream", ProviderType = musicType, Query = query - }); + }) + { TotalLength = TimeSpan.MaxValue }; } if (SoundCloud.Default.IsSoundCloudLink(query)) { @@ -275,7 +285,8 @@ namespace NadekoBot.Modules.Music.Classes Uri = svideo.StreamLink, ProviderType = musicType, Query = svideo.TrackLink, - }); + }) + { TotalLength = TimeSpan.FromMilliseconds(svideo.Duration) }; } if (musicType == MusicType.Soundcloud) @@ -288,7 +299,8 @@ namespace NadekoBot.Modules.Music.Classes Uri = svideo.StreamLink, ProviderType = MusicType.Normal, Query = svideo.TrackLink, - }); + }) + { TotalLength = TimeSpan.FromMilliseconds(svideo.Duration) }; } var link = (await NadekoBot.Google.GetVideosByKeywordsAsync(query).ConfigureAwait(false)).FirstOrDefault(); diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index a7490395..6b58d21b 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -141,6 +141,12 @@ namespace NadekoBot.Modules.Music var currentSong = musicPlayer.CurrentSong; if (currentSong == null) return; + + if (currentSong.TotalLength == TimeSpan.Zero) + { + await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + } + var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n"; if (musicPlayer.RepeatSong) toSend += "🔂"; @@ -168,6 +174,11 @@ namespace NadekoBot.Modules.Music var currentSong = musicPlayer.CurrentSong; if (currentSong == null) return; + + if (currentSong.TotalLength == TimeSpan.Zero) + { + await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + } await channel.SendMessageAsync($"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}").ConfigureAwait(false); } diff --git a/src/NadekoBot/Services/IGoogleApiService.cs b/src/NadekoBot/Services/IGoogleApiService.cs index 43d0f4da..b79bdb64 100644 --- a/src/NadekoBot/Services/IGoogleApiService.cs +++ b/src/NadekoBot/Services/IGoogleApiService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace NadekoBot.Services @@ -9,6 +10,7 @@ namespace NadekoBot.Services Task> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1); Task> GetRelatedVideosAsync(string url, int count = 1); Task> GetPlaylistTracksAsync(string playlistId, int count = 50); + Task> GetVideoDurationsAsync(IEnumerable videoIds); Task ShortenUrl(string url); } diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 0264e351..5d578dc1 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -8,6 +8,7 @@ using System.Text.RegularExpressions; using Google.Apis.Urlshortener.v1; using Google.Apis.Urlshortener.v1.Data; using NLog; +using System.Collections; namespace NadekoBot.Services.Impl { @@ -133,5 +134,34 @@ namespace NadekoBot.Services.Impl return toReturn; } + + public async Task> GetVideoDurationsAsync(IEnumerable videoIds) + { + var videoIdsList = videoIds as List ?? videoIds.ToList(); + + Dictionary toReturn = new Dictionary(); + + if (!videoIdsList.Any()) + return toReturn; + var toGet = 0; + var remaining = videoIdsList.Count; + + do + { + toGet = remaining > 50 ? 50 : remaining; + remaining -= toGet; + + var q = yt.Videos.List("contentDetails"); + q.Id = string.Join(",", videoIds); + var items = (await q.ExecuteAsync().ConfigureAwait(false)).Items; + foreach (var i in items) + { + toReturn.Add(i.Id, System.Xml.XmlConvert.ToTimeSpan(i.ContentDetails.Duration)); + } + } + while (remaining > 0); + + return toReturn; + } } }