215 lines
5.4 KiB
C#
215 lines
5.4 KiB
C#
|
using NadekoBot.Extensions;
|
|||
|
using NadekoBot.Modules.Music.Common.Exceptions;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using NadekoBot.Common;
|
|||
|
|
|||
|
namespace NadekoBot.Modules.Music.Common
|
|||
|
{
|
|||
|
public class MusicQueue : IDisposable
|
|||
|
{
|
|||
|
private LinkedList<SongInfo> Songs { get; set; } = new LinkedList<SongInfo>();
|
|||
|
private int _currentIndex = 0;
|
|||
|
public int CurrentIndex
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _currentIndex;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
if (Songs.Count == 0)
|
|||
|
_currentIndex = 0;
|
|||
|
else
|
|||
|
_currentIndex = value %= Songs.Count;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
public (int Index, SongInfo Song) Current
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
var cur = CurrentIndex;
|
|||
|
return (cur, Songs.ElementAtOrDefault(cur));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private readonly object locker = new object();
|
|||
|
private TaskCompletionSource<bool> nextSource { get; } = new TaskCompletionSource<bool>();
|
|||
|
public int Count
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
return Songs.Count;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private uint _maxQueueSize;
|
|||
|
public uint MaxQueueSize
|
|||
|
{
|
|||
|
get => _maxQueueSize;
|
|||
|
set
|
|||
|
{
|
|||
|
if (value < 0)
|
|||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
|||
|
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
_maxQueueSize = value;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Add(SongInfo song)
|
|||
|
{
|
|||
|
song.ThrowIfNull(nameof(song));
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
if(MaxQueueSize != 0 && Songs.Count >= MaxQueueSize)
|
|||
|
throw new QueueFullException();
|
|||
|
Songs.AddLast(song);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public int AddNext(SongInfo song)
|
|||
|
{
|
|||
|
song.ThrowIfNull(nameof(song));
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
if (MaxQueueSize != 0 && Songs.Count >= MaxQueueSize)
|
|||
|
throw new QueueFullException();
|
|||
|
var curSong = Current.Song;
|
|||
|
if (curSong == null)
|
|||
|
{
|
|||
|
Songs.AddLast(song);
|
|||
|
return Songs.Count;
|
|||
|
}
|
|||
|
|
|||
|
var songlist = Songs.ToList();
|
|||
|
songlist.Insert(CurrentIndex + 1, song);
|
|||
|
Songs = new LinkedList<SongInfo>(songlist);
|
|||
|
return CurrentIndex + 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Next(int skipCount = 1)
|
|||
|
{
|
|||
|
lock(locker)
|
|||
|
CurrentIndex += skipCount;
|
|||
|
}
|
|||
|
|
|||
|
public void Dispose()
|
|||
|
{
|
|||
|
Clear();
|
|||
|
}
|
|||
|
|
|||
|
public SongInfo RemoveAt(int index)
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
if (index < 0 || index >= Songs.Count)
|
|||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
|||
|
|
|||
|
var current = Songs.First.Value;
|
|||
|
for (int i = 0; i < Songs.Count; i++)
|
|||
|
{
|
|||
|
if (i == index)
|
|||
|
{
|
|||
|
current = Songs.ElementAt(index);
|
|||
|
Songs.Remove(current);
|
|||
|
if (CurrentIndex != 0)
|
|||
|
{
|
|||
|
if (CurrentIndex >= index)
|
|||
|
{
|
|||
|
--CurrentIndex;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return current;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Clear()
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
Songs.Clear();
|
|||
|
CurrentIndex = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public (int CurrentIndex, SongInfo[] Songs) ToArray()
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
return (CurrentIndex, Songs.ToArray());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ResetCurrent()
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
CurrentIndex = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Random()
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
CurrentIndex = new NadekoRandom().Next(Songs.Count);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public SongInfo MoveSong(int n1, int n2)
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
var currentSong = Current.Song;
|
|||
|
var playlist = Songs.ToList();
|
|||
|
if (n1 >= playlist.Count || n2 >= playlist.Count || n1 == n2)
|
|||
|
return null;
|
|||
|
|
|||
|
var s = playlist[n1];
|
|||
|
|
|||
|
playlist.RemoveAt(n1);
|
|||
|
playlist.Insert(n2, s);
|
|||
|
|
|||
|
Songs = new LinkedList<SongInfo>(playlist);
|
|||
|
|
|||
|
|
|||
|
if (currentSong != null)
|
|||
|
CurrentIndex = playlist.IndexOf(currentSong);
|
|||
|
|
|||
|
return s;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void RemoveSong(SongInfo song)
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
{
|
|||
|
Songs.Remove(song);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool IsLast()
|
|||
|
{
|
|||
|
lock (locker)
|
|||
|
return CurrentIndex == Songs.Count - 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//O O [O] O O O O
|
|||
|
//
|
|||
|
// 3
|