INIT
This commit is contained in:
72
TomatenMusicCore/Music/Entitites/FullTrackContext.cs
Normal file
72
TomatenMusicCore/Music/Entitites/FullTrackContext.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TomatenMusic.Services;
|
||||
using System.Linq;
|
||||
using SpotifyAPI.Web;
|
||||
using Lavalink4NET.Player;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Lavalink4NET;
|
||||
using TomatenMusicCore.Music;
|
||||
using TomatenMusicCore.Music.Entities;
|
||||
|
||||
namespace TomatenMusic.Music.Entitites
|
||||
{
|
||||
public class FullTrackContext
|
||||
{
|
||||
public bool IsFile { get; set; }
|
||||
public string YoutubeDescription { get; set; }
|
||||
public IEnumerable<string> YoutubeTags { get; set; }
|
||||
public ulong YoutubeViews { get; set; }
|
||||
public ulong YoutubeLikes { get; set; }
|
||||
public Uri YoutubeThumbnail { get; set; }
|
||||
public DateTime YoutubeUploadDate { get; set; }
|
||||
//
|
||||
// Summary:
|
||||
// Gets the author of the track.
|
||||
public Uri YoutubeAuthorThumbnail { get; set; }
|
||||
public ulong YoutubeAuthorSubs { get; set; }
|
||||
public Uri YoutubeAuthorUri { get; set; }
|
||||
public ulong? YoutubeCommentCount { get; set; }
|
||||
public string SpotifyIdentifier { get; set; }
|
||||
public SimpleAlbum SpotifyAlbum { get; set; }
|
||||
public List<SimpleArtist> SpotifyArtists { get; set; }
|
||||
public int SpotifyPopularity { get; set; }
|
||||
public Uri SpotifyUri { get; set; }
|
||||
|
||||
public static async Task<TomatenMusicTrack> PopulateAsync(TomatenMusicTrack track, FullTrack spotifyTrack = null, string spotifyId = null)
|
||||
{
|
||||
FullTrackContext context = (FullTrackContext)track.Context;
|
||||
|
||||
if (context == null)
|
||||
context = new FullTrackContext();
|
||||
|
||||
var spotifyService = TomatenMusicBot.ServiceProvider.GetRequiredService<ISpotifyService>();
|
||||
var youtubeService = TomatenMusicBot.ServiceProvider.GetRequiredService<YoutubeService>();
|
||||
if (spotifyId != null)
|
||||
context.SpotifyIdentifier = spotifyId;
|
||||
else if (spotifyTrack != null)
|
||||
context.SpotifyIdentifier = spotifyTrack.Id;
|
||||
|
||||
track.Context = context;
|
||||
await youtubeService.PopulateTrackInfoAsync(track);
|
||||
await spotifyService.PopulateTrackAsync(track, spotifyTrack);
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
public static async Task<TrackList> PopulateTracksAsync(TrackList tracks)
|
||||
{
|
||||
foreach (var trackItem in tracks)
|
||||
{
|
||||
await PopulateAsync(trackItem);
|
||||
}
|
||||
|
||||
return tracks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
36
TomatenMusicCore/Music/Entitites/ILavalinkPlaylist.cs
Normal file
36
TomatenMusicCore/Music/Entitites/ILavalinkPlaylist.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using TomatenMusic.Util;
|
||||
using DSharpPlus.Entities;
|
||||
using Lavalink4NET.Player;
|
||||
using TomatenMusicCore.Music;
|
||||
using TomatenMusicCore.Music.Entities;
|
||||
|
||||
namespace TomatenMusic.Music.Entitites
|
||||
{
|
||||
public interface ILavalinkPlaylist : IPlayableItem
|
||||
{
|
||||
public string Title { get; }
|
||||
public TrackList Tracks { get; }
|
||||
public Uri Url { get; }
|
||||
public string AuthorName { get; set; }
|
||||
public Uri AuthorUri { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Identifier { get; }
|
||||
public Uri AuthorThumbnail { get; set; }
|
||||
|
||||
public TimeSpan GetLength()
|
||||
{
|
||||
TimeSpan timeSpan = TimeSpan.FromTicks(0);
|
||||
|
||||
foreach (var track in Tracks)
|
||||
{
|
||||
timeSpan = timeSpan.Add(track.Duration);
|
||||
}
|
||||
|
||||
return timeSpan;
|
||||
}
|
||||
}
|
||||
}
|
17
TomatenMusicCore/Music/Entitites/IPlayableItem.cs
Normal file
17
TomatenMusicCore/Music/Entitites/IPlayableItem.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TomatenMusic.Music;
|
||||
|
||||
namespace TomatenMusicCore.Music.Entities
|
||||
{
|
||||
public interface IPlayableItem
|
||||
{
|
||||
public string Title { get; }
|
||||
Task Play(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool noReplace = true);
|
||||
Task PlayNow(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool withoutQueuePrepend = false);
|
||||
|
||||
}
|
||||
}
|
63
TomatenMusicCore/Music/Entitites/SpotifyPlaylist.cs
Normal file
63
TomatenMusicCore/Music/Entitites/SpotifyPlaylist.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Lavalink4NET.Player;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using TomatenMusicCore.Music;
|
||||
using TomatenMusicCore.Music.Entities;
|
||||
|
||||
namespace TomatenMusic.Music.Entitites
|
||||
{
|
||||
public class SpotifyPlaylist : ILavalinkPlaylist
|
||||
{
|
||||
public string Title { get; }
|
||||
public TrackList Tracks { get; }
|
||||
public Uri Url { get; set; }
|
||||
public string AuthorName { get; set; }
|
||||
public Uri AuthorUri { get; set; }
|
||||
public string Description { get; set; }
|
||||
public int Followers { get; set; }
|
||||
public string Identifier { get; }
|
||||
public Uri AuthorThumbnail { get; set; }
|
||||
|
||||
public SpotifyPlaylist(string name, string id, TrackList tracks, Uri uri)
|
||||
{
|
||||
Title = name;
|
||||
Identifier = id;
|
||||
Tracks = tracks;
|
||||
Url = uri;
|
||||
}
|
||||
|
||||
public async Task Play(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool noReplace = true)
|
||||
{
|
||||
await player.PlayerQueue.QueuePlaylistAsync(this);
|
||||
|
||||
|
||||
if (player.State == PlayerState.NotPlaying)
|
||||
{
|
||||
LavalinkTrack nextTrack = player.PlayerQueue.NextTrack().Track;
|
||||
await player.PlayAsync(nextTrack);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PlayNow(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool withoutQueuePrepend = false)
|
||||
{
|
||||
if (!player.PlayerQueue.Queue.Any())
|
||||
player.PlayerQueue.CurrentPlaylist = this;
|
||||
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(new TomatenMusicTrack(player.PlayerQueue.LastTrack.WithPosition(player.TrackPosition))));
|
||||
|
||||
Queue<TomatenMusicTrack> reversedTracks = new Queue<TomatenMusicTrack>(Tracks);
|
||||
|
||||
TomatenMusicTrack track = reversedTracks.Dequeue();
|
||||
player.PlayerQueue.LastTrack = track;
|
||||
await player.PlayAsync(track);
|
||||
|
||||
reversedTracks.Reverse();
|
||||
|
||||
foreach (var item in reversedTracks)
|
||||
{
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
TomatenMusicCore/Music/Entitites/TomatenMusicTrack.cs
Normal file
50
TomatenMusicCore/Music/Entitites/TomatenMusicTrack.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Lavalink4NET.Player;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TomatenMusic.Music;
|
||||
using TomatenMusic.Prompt.Implementation;
|
||||
|
||||
namespace TomatenMusicCore.Music.Entities
|
||||
{
|
||||
public class TomatenMusicTrack : LavalinkTrack, IPlayableItem
|
||||
{
|
||||
|
||||
public override TimeSpan Position { get; }
|
||||
public TomatenMusicTrack
|
||||
(LavalinkTrack track)
|
||||
: base(track.Identifier, track.Author, track.Duration, track.IsLiveStream, track.IsSeekable, track.Source, track.Title, track.TrackIdentifier, track.Provider)
|
||||
{
|
||||
Context = track.Context;
|
||||
Position = track.Position;
|
||||
}
|
||||
|
||||
public string Title => base.Title;
|
||||
|
||||
public async Task Play(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool noReplace = true)
|
||||
{
|
||||
|
||||
if (player.State == PlayerState.NotPlaying)
|
||||
{
|
||||
player.PlayerQueue.LastTrack = this;
|
||||
await player.PlayAsync(this, startTime, endTime, noReplace);
|
||||
}
|
||||
else
|
||||
player.PlayerQueue.QueueTrack(this);
|
||||
|
||||
}
|
||||
|
||||
public async Task PlayNow(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool withoutQueuePrepend = false)
|
||||
{
|
||||
if (!withoutQueuePrepend)
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(new TomatenMusicTrack(player.PlayerQueue.LastTrack.WithPosition(player.TrackPosition))));
|
||||
|
||||
|
||||
player.PlayerQueue.LastTrack = this;
|
||||
await player.PlayAsync(this, startTime, endTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
567
TomatenMusicCore/Music/Entitites/TrackList.cs
Normal file
567
TomatenMusicCore/Music/Entitites/TrackList.cs
Normal file
@@ -0,0 +1,567 @@
|
||||
|
||||
|
||||
using Lavalink4NET.Player;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TomatenMusic.Music;
|
||||
|
||||
namespace TomatenMusicCore.Music.Entities
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// A thread-safe queue for Lavalink4NET.Player.LavalinkTrack.
|
||||
public sealed class TrackList : IList<TomatenMusicTrack>, ICollection<TomatenMusicTrack>, IEnumerable<TomatenMusicTrack>, IEnumerable, IPlayableItem
|
||||
{
|
||||
private readonly List<TomatenMusicTrack> _list;
|
||||
|
||||
private readonly object _syncRoot;
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets the number of queued tracks.
|
||||
//
|
||||
// Remarks:
|
||||
// This property is thread-safe, so it can be used from multiple threads at once
|
||||
// safely.
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets a value indicating whether the queue is empty.
|
||||
//
|
||||
// Remarks:
|
||||
// This property is thread-safe, so it can be used from multiple threads at once
|
||||
// safely.
|
||||
public bool IsEmpty => Count == 0;
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets a value indicating whether the queue is read-only.
|
||||
//
|
||||
// Remarks:
|
||||
// This property is thread-safe, so it can be used from multiple threads at once
|
||||
// safely.
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets or sets the enqueued tracks.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public IReadOnlyList<TomatenMusicTrack> Tracks
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.ToArray();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.Clear();
|
||||
_list.AddRange(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Title => $"Track List with {Count} Tracks";
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets or sets the track at the specified index.
|
||||
//
|
||||
// Parameters:
|
||||
// index:
|
||||
// the zero-based position
|
||||
//
|
||||
// Returns:
|
||||
// the track at the specified index
|
||||
//
|
||||
// Remarks:
|
||||
// This indexer property is thread-safe, so it can be used from multiple threads
|
||||
// at once safely.
|
||||
public TomatenMusicTrack this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list[index];
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list[index] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TrackList()
|
||||
{
|
||||
_list = new List<TomatenMusicTrack>();
|
||||
_syncRoot = new object();
|
||||
}
|
||||
|
||||
public TrackList(IEnumerable<LavalinkTrack> tracks)
|
||||
{
|
||||
_list = new List<TomatenMusicTrack>();
|
||||
_syncRoot = new object();
|
||||
|
||||
foreach (var track in tracks)
|
||||
Add(new TomatenMusicTrack(track));
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Adds a track at the end of the queue.
|
||||
//
|
||||
// Parameters:
|
||||
// track:
|
||||
// the track to add
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.ArgumentNullException:
|
||||
// thrown if the specified track is null.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void Add(TomatenMusicTrack track)
|
||||
{
|
||||
if (track == null)
|
||||
{
|
||||
throw new ArgumentNullException("track");
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.Add(track);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Adds all specified tracks to the queue.
|
||||
//
|
||||
// Parameters:
|
||||
// tracks:
|
||||
// the tracks to enqueue
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.ArgumentNullException:
|
||||
// thrown if the specified tracks enumerable is null.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void AddRange(IEnumerable<TomatenMusicTrack> tracks)
|
||||
{
|
||||
if (tracks == null)
|
||||
{
|
||||
throw new ArgumentNullException("tracks");
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.AddRange(tracks);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Clears all tracks from the queue.
|
||||
//
|
||||
// Returns:
|
||||
// the number of tracks removed
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public int Clear()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
int count = _list.Count;
|
||||
_list.Clear();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets a value indicating whether the specified track is in the queue.
|
||||
//
|
||||
// Parameters:
|
||||
// track:
|
||||
// the track to find
|
||||
//
|
||||
// Returns:
|
||||
// a value indicating whether the specified track is in the queue
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public bool Contains(TomatenMusicTrack track)
|
||||
{
|
||||
if (track == null)
|
||||
{
|
||||
throw new ArgumentNullException("track");
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.Contains(track);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Copies all tracks to the specified array at the specified index.
|
||||
//
|
||||
// Parameters:
|
||||
// array:
|
||||
// the array to the tracks to
|
||||
//
|
||||
// index:
|
||||
// the zero-based writing start index
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void CopyTo(TomatenMusicTrack[] array, int index)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.CopyTo(array, index);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Dequeues a track using the FIFO method.
|
||||
//
|
||||
// Returns:
|
||||
// the dequeued track
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.InvalidOperationException:
|
||||
// thrown if no tracks were in the queue
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public TomatenMusicTrack Dequeue()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_list.Count <= 0)
|
||||
{
|
||||
throw new InvalidOperationException("No tracks in to dequeue.");
|
||||
}
|
||||
|
||||
TomatenMusicTrack result = _list[0];
|
||||
_list.RemoveAt(0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Deletes all duplicate tracks from the queue.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void Distinct()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_list.Count > 1)
|
||||
{
|
||||
TomatenMusicTrack[] collection = (from track in _list
|
||||
group track by track.Identifier into s
|
||||
select s.First()).ToArray();
|
||||
_list.Clear();
|
||||
_list.AddRange(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets the track enumerator.
|
||||
//
|
||||
// Returns:
|
||||
// the track enumerator
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public IEnumerator<TomatenMusicTrack> GetEnumerator()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.ToList().GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets the zero-based index of the specified track.
|
||||
//
|
||||
// Parameters:
|
||||
// track:
|
||||
// the track to locate
|
||||
//
|
||||
// Returns:
|
||||
// the zero-based index of the specified track
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.ArgumentNullException:
|
||||
// thrown if the specified track is null.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public int IndexOf(TomatenMusicTrack track)
|
||||
{
|
||||
if (track == null)
|
||||
{
|
||||
throw new ArgumentNullException("track");
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.IndexOf(track);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Inserts the specified track at the specified index.
|
||||
//
|
||||
// Parameters:
|
||||
// index:
|
||||
// the zero-based index to insert (e.g. 0 = top)
|
||||
//
|
||||
// track:
|
||||
// the track to insert
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void Insert(int index, TomatenMusicTrack track)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.Insert(index, track);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Tries to remove the specified track from the queue.
|
||||
//
|
||||
// Parameters:
|
||||
// track:
|
||||
// the track to remove
|
||||
//
|
||||
// Returns:
|
||||
// a value indicating whether the track was found and removed from the queue
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public bool Remove(TomatenMusicTrack track)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.Remove(track);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Removes all tracks that matches the specified predicate.
|
||||
//
|
||||
// Parameters:
|
||||
// predicate:
|
||||
// the track predicate
|
||||
//
|
||||
// Returns:
|
||||
// the number of tracks removed
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public int RemoveAll(Predicate<TomatenMusicTrack> predicate)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.RemoveAll(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Removes a track at the specified index.
|
||||
//
|
||||
// Parameters:
|
||||
// index:
|
||||
// the index to remove the track
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Removes all count tracks from the specified index.
|
||||
//
|
||||
// Parameters:
|
||||
// index:
|
||||
// the start index (zero-based)
|
||||
//
|
||||
// count:
|
||||
// the number of tracks to remove
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void RemoveRange(int index, int count)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.RemoveRange(index, count);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Shuffles / mixes all tracks in the queue.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public void Shuffle()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_list.Count > 2)
|
||||
{
|
||||
TomatenMusicTrack[] collection = _list.OrderBy((TomatenMusicTrack s) => Guid.NewGuid()).ToArray();
|
||||
_list.Clear();
|
||||
_list.AddRange(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Tries to dequeue a track using the FIFO method.
|
||||
//
|
||||
// Parameters:
|
||||
// track:
|
||||
// the dequeued track; or default is the result is false.
|
||||
//
|
||||
// Returns:
|
||||
// a value indicating whether a track was dequeued.
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.InvalidOperationException:
|
||||
// thrown if no tracks were in the queue
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
public bool TryDequeue(out TomatenMusicTrack? track)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_list.Count <= 0)
|
||||
{
|
||||
track = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
track = _list[0];
|
||||
_list.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Clears the queue.
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
void ICollection<TomatenMusicTrack>.Clear()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_list.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Gets the track enumerator.
|
||||
//
|
||||
// Returns:
|
||||
// the track enumerator
|
||||
//
|
||||
// Remarks:
|
||||
// This method is thread-safe, so it can be used from multiple threads at once safely.
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _list.ToArray().GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Play(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool noReplace = true)
|
||||
{
|
||||
await player.PlayerQueue.QueueTracksAsync(this);
|
||||
|
||||
if (player.State == PlayerState.NotPlaying)
|
||||
{
|
||||
LavalinkTrack nextTrack = player.PlayerQueue.NextTrack().Track;
|
||||
await player.PlayAsync(nextTrack, startTime, endTime, noReplace);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PlayNow(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool withoutQueuePrepend = false)
|
||||
{
|
||||
Queue<TomatenMusicTrack> reversedTracks = new Queue<TomatenMusicTrack>(this);
|
||||
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(new TomatenMusicTrack(player.PlayerQueue.LastTrack.WithPosition(player.TrackPosition))));
|
||||
|
||||
TomatenMusicTrack track = reversedTracks.Dequeue();
|
||||
player.PlayerQueue.LastTrack = track;
|
||||
await player.PlayAsync(track, startTime, endTime);
|
||||
|
||||
reversedTracks.Reverse();
|
||||
|
||||
foreach (var item in reversedTracks)
|
||||
{
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
TomatenMusicCore/Music/Entitites/YoutubePlaylist.cs
Normal file
77
TomatenMusicCore/Music/Entitites/YoutubePlaylist.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Lavalink4NET.Player;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TomatenMusic.Services;
|
||||
using TomatenMusicCore.Music;
|
||||
using TomatenMusicCore.Music.Entities;
|
||||
|
||||
namespace TomatenMusic.Music.Entitites
|
||||
{
|
||||
public class YoutubePlaylist : ILavalinkPlaylist
|
||||
{
|
||||
public string Title { get; }
|
||||
|
||||
public TrackList Tracks { get; }
|
||||
|
||||
public int TrackCount { get; }
|
||||
|
||||
public Uri Url { get; }
|
||||
|
||||
public string AuthorName { get; set; }
|
||||
public Uri AuthorUri { get; set; }
|
||||
public string Description { get; set; }
|
||||
public Uri Thumbnail { get; set; }
|
||||
public DateTime CreationTime { get; set; }
|
||||
public string Identifier { get; }
|
||||
public Playlist YoutubeItem { get; set; }
|
||||
public Uri AuthorThumbnail { get; set; }
|
||||
|
||||
public YoutubePlaylist(string name, TrackList tracks, string id)
|
||||
{
|
||||
Identifier = id;
|
||||
Title = name;
|
||||
Tracks = tracks;
|
||||
Url = new Uri($"https://youtube.com/playlist?list={id}");
|
||||
TrackCount = tracks.Count();
|
||||
|
||||
}
|
||||
|
||||
public async Task Play(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool noReplace = true)
|
||||
{
|
||||
await player.PlayerQueue.QueuePlaylistAsync(this);
|
||||
|
||||
|
||||
if (player.State == PlayerState.NotPlaying)
|
||||
{
|
||||
LavalinkTrack nextTrack = player.PlayerQueue.NextTrack().Track;
|
||||
await player.PlayAsync(nextTrack);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PlayNow(GuildPlayer player, TimeSpan? startTime = null, TimeSpan? endTime = null, bool withoutQueuePrepend = false)
|
||||
{
|
||||
if (!player.PlayerQueue.Queue.Any())
|
||||
player.PlayerQueue.CurrentPlaylist = this;
|
||||
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(new TomatenMusicTrack(player.PlayerQueue.LastTrack.WithPosition(player.TrackPosition))));
|
||||
|
||||
|
||||
Queue<TomatenMusicTrack> reversedTracks = new Queue<TomatenMusicTrack>(Tracks);
|
||||
|
||||
TomatenMusicTrack track = reversedTracks.Dequeue();
|
||||
player.PlayerQueue.LastTrack = track;
|
||||
await player.PlayAsync(track);
|
||||
|
||||
reversedTracks.Reverse();
|
||||
|
||||
foreach (var item in reversedTracks)
|
||||
{
|
||||
player.PlayerQueue.Queue = new Queue<TomatenMusicTrack>(player.PlayerQueue.Queue.Prepend(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user