woops, didn't push csproj

This commit is contained in:
Master Kwoth
2016-04-15 00:30:34 +02:00
parent a0f14c9cd9
commit 1617994e20
31 changed files with 84 additions and 395 deletions

View File

@ -1,8 +1,8 @@
using Discord;
using Discord.Commands;
using Discord.Modules;
using NadekoBot._DataModels;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Commands;
using NadekoBot.Modules.Permissions.Classes;
@ -727,7 +727,7 @@ namespace NadekoBot.Modules.Administration
await Task.Run(() =>
{
SaveParseToDb<Announcement>("data/parsedata/Announcements.json");
SaveParseToDb<Classes._DataModels.Command>("data/parsedata/CommandsRan.json");
SaveParseToDb<_DataModels.Command>("data/parsedata/CommandsRan.json");
SaveParseToDb<Request>("data/parsedata/Requests.json");
SaveParseToDb<Stats>("data/parsedata/Stats.json");
SaveParseToDb<TypingArticle>("data/parsedata/TypingArticles.json");

View File

@ -1,7 +1,7 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot._DataModels;
using NadekoBot.Classes;
using System;
using System.Collections.Generic;

View File

@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Administration.Commands
NadekoBot.Client.UserJoined += UserJoined;
NadekoBot.Client.UserLeft += UserLeft;
var data = Classes.DbHandler.Instance.GetAllRows<Classes._DataModels.Announcement>();
var data = Classes.DbHandler.Instance.GetAllRows<_DataModels.Announcement>();
if (!data.Any()) return;
foreach (var obj in data)
@ -114,7 +114,7 @@ namespace NadekoBot.Modules.Administration.Commands
public class AnnounceControls
{
private Classes._DataModels.Announcement _model { get; }
private _DataModels.Announcement _model { get; }
public bool Greet {
get { return _model.Greet; }
@ -160,14 +160,14 @@ namespace NadekoBot.Modules.Administration.Commands
set { _model.ServerId = (long)value; }
}
public AnnounceControls(Classes._DataModels.Announcement model)
public AnnounceControls(_DataModels.Announcement model)
{
this._model = model;
}
public AnnounceControls(ulong serverId)
{
this._model = new Classes._DataModels.Announcement();
this._model = new _DataModels.Announcement();
ServerId = serverId;
}

View File

@ -10,7 +10,7 @@ namespace NadekoBot.Classes.Conversations.Commands
{
public void SaveRequest(CommandEventArgs e, string text)
{
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Request
DbHandler.Instance.InsertData(new _DataModels.Request
{
RequestText = text,
UserName = e.User.Name,
@ -23,7 +23,7 @@ namespace NadekoBot.Classes.Conversations.Commands
// todo what if it's too long?
public string GetRequests()
{
var task = Classes.DbHandler.Instance.GetAllRows<Classes._DataModels.Request>();
var task = DbHandler.Instance.GetAllRows<_DataModels.Request>();
var str = "Here are all current requests for NadekoBot:\n\n";
foreach (var reqObj in task)
@ -35,14 +35,14 @@ namespace NadekoBot.Classes.Conversations.Commands
}
public bool DeleteRequest(int requestNumber) =>
Classes.DbHandler.Instance.Delete<Classes._DataModels.Request>(requestNumber) != null;
DbHandler.Instance.Delete<_DataModels.Request>(requestNumber) != null;
/// <summary>
/// Delete a request with a number and returns that request object.
/// </summary>
/// <returns>RequestObject of the request. Null if none</returns>
public Classes._DataModels.Request ResolveRequest(int requestNumber) =>
Classes.DbHandler.Instance.Delete<Classes._DataModels.Request>(requestNumber);
public _DataModels.Request ResolveRequest(int requestNumber) =>
DbHandler.Instance.Delete<_DataModels.Request>(requestNumber);
internal override void Init(CommandGroupBuilder cgb)
{

View File

@ -89,7 +89,7 @@ namespace NadekoBot.Modules.Conversations
if (string.IsNullOrWhiteSpace(text))
return;
await Task.Run(() =>
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.UserQuote()
Classes.DbHandler.Instance.InsertData(new _DataModels.UserQuote()
{
DateAdded = DateTime.Now,
Keyword = e.GetArg("keyword").ToLowerInvariant(),
@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Conversations
return;
var quote =
Classes.DbHandler.Instance.GetRandom<Classes._DataModels.UserQuote>(
Classes.DbHandler.Instance.GetRandom<_DataModels.UserQuote>(
uqm => uqm.Keyword == keyword);
if (quote != null)

View File

@ -1,7 +1,7 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot._DataModels;
using NadekoBot.Classes;
using NadekoBot.Extensions;
using System;

View File

@ -0,0 +1,231 @@
using Discord;
using Discord.Audio;
using NadekoBot.Extensions;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Music.Classes
{
public enum MusicType
{
Radio,
Normal,
Local
}
public enum StreamState
{
Resolving,
Queued,
Buffering, //not using it atm
Playing,
Completed
}
public class MusicPlayer
{
public static int MaximumPlaylistSize => 50;
private IAudioClient audioClient { get; set; }
private readonly List<Song> playlist = new List<Song>();
public IReadOnlyCollection<Song> Playlist => playlist;
private readonly object playlistLock = new object();
public Song CurrentSong { get; set; } = default(Song);
private CancellationTokenSource SongCancelSource { get; set; }
private CancellationToken cancelToken { get; set; }
public bool Paused { get; set; }
public float Volume { get; private set; }
public event EventHandler<Song> OnCompleted = delegate { };
public event EventHandler<Song> OnStarted = delegate { };
public Channel PlaybackVoiceChannel { get; private set; }
private bool Destroyed { get; set; } = false;
public bool RepeatSong { get; private set; } = false;
public bool RepeatPlaylist { get; private set; } = false;
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume)
{
if (startingVoiceChannel == null)
throw new ArgumentNullException(nameof(startingVoiceChannel));
if (startingVoiceChannel.Type != ChannelType.Voice)
throw new ArgumentException("Channel must be of type voice");
Volume = defaultVolume ?? 1.0f;
PlaybackVoiceChannel = startingVoiceChannel;
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
Task.Run(async () =>
{
while (!Destroyed)
{
try
{
if (audioClient?.State != ConnectionState.Connected)
audioClient = await PlaybackVoiceChannel.JoinAudio();
}
catch
{
await Task.Delay(1000);
continue;
}
CurrentSong = GetNextSong();
var curSong = CurrentSong;
if (curSong != null)
{
try
{
OnStarted(this, curSong);
await curSong.Play(audioClient, cancelToken);
}
catch (OperationCanceledException)
{
Console.WriteLine("Song canceled");
}
catch (Exception ex)
{
Console.WriteLine($"Exception in PlaySong: {ex}");
}
OnCompleted(this, curSong);
if (RepeatSong)
playlist.Insert(0, curSong);
else if (RepeatPlaylist)
playlist.Insert(playlist.Count, curSong);
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
}
await Task.Delay(1000);
}
});
}
public void Next()
{
lock (playlistLock)
{
if (!SongCancelSource.IsCancellationRequested)
{
Paused = false;
SongCancelSource.Cancel();
}
}
}
public void Stop()
{
lock (playlistLock)
{
playlist.Clear();
CurrentSong = null;
RepeatPlaylist = false;
RepeatSong = false;
if (!SongCancelSource.IsCancellationRequested)
SongCancelSource.Cancel();
}
}
public void TogglePause() => Paused = !Paused;
public void Shuffle()
{
lock (playlistLock)
{
playlist.Shuffle();
}
}
public int SetVolume(int volume)
{
if (volume < 0)
volume = 0;
if (volume > 100)
volume = 100;
Volume = volume / 100.0f;
return volume;
}
private Song GetNextSong()
{
lock (playlistLock)
{
if (playlist.Count == 0)
return null;
var toReturn = playlist[0];
playlist.RemoveAt(0);
return toReturn;
}
}
public void AddSong(Song s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
lock (playlistLock)
{
playlist.Add(s);
}
}
public void RemoveSong(Song s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
lock (playlistLock)
{
playlist.Remove(s);
}
}
public void RemoveSongAt(int index)
{
lock (playlistLock)
{
if (index < 0 || index >= playlist.Count)
throw new ArgumentException("Invalid index");
playlist.RemoveAt(index);
}
}
internal Task MoveToVoiceChannel(Channel voiceChannel)
{
if (audioClient?.State != ConnectionState.Connected)
throw new InvalidOperationException("Can't move while bot is not connected to voice channel.");
PlaybackVoiceChannel = voiceChannel;
return PlaybackVoiceChannel.JoinAudio();
}
internal void ClearQueue()
{
lock (playlistLock)
{
playlist.Clear();
}
}
public void Destroy()
{
lock (playlistLock)
{
playlist.Clear();
Destroyed = true;
CurrentSong = null;
if (!SongCancelSource.IsCancellationRequested)
SongCancelSource.Cancel();
audioClient.Disconnect();
}
}
internal bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong;
internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist;
}
}

View File

@ -0,0 +1,120 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Music.Classes
{
/// <summary>
/// 💩
/// </summary>
public class PoopyBuffer
{
private readonly byte[] ringBuffer;
public int WritePosition { get; private set; } = 0;
public int ReadPosition { get; private set; } = 0;
public int ContentLength => (WritePosition >= ReadPosition ?
WritePosition - ReadPosition :
(BufferSize - ReadPosition) + WritePosition);
public int BufferSize { get; }
private readonly object readWriteLock = new object();
public PoopyBuffer(int size)
{
if (size <= 0)
throw new ArgumentException();
BufferSize = size;
ringBuffer = new byte[size];
}
public int Read(byte[] buffer, int count)
{
if (buffer.Length < count)
throw new ArgumentException();
//Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***");
lock (readWriteLock)
{
//read as much as you can if you're reading too much
if (count > ContentLength)
count = ContentLength;
//if nothing to read, return 0
if (WritePosition == ReadPosition)
return 0;
// if buffer is in the "normal" state, just read
if (WritePosition > ReadPosition)
{
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
ReadPosition += count;
//Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]");
return count;
}
//else ReadPos <Writepos
// buffer is in its inverted state
// A: if i can read as much as possible without hitting the buffer.length, read that
if (count + ReadPosition <= BufferSize)
{
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
ReadPosition += count;
//Console.WriteLine($"Read only normally2 {count}[{ReadPosition - count} to {ReadPosition}]");
return count;
}
// B: if i can't read as much, read to the end,
var readNormaly = BufferSize - ReadPosition;
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, readNormaly);
//Console.WriteLine($"Read normaly {count}[{ReadPosition} to {ReadPosition + readNormaly}]");
//then read the remaining amount from the start
var readFromStart = count - readNormaly;
Buffer.BlockCopy(ringBuffer, 0, buffer, readNormaly, readFromStart);
//Console.WriteLine($"Read From start {readFromStart}[{0} to {readFromStart}]");
ReadPosition = readFromStart;
return count;
}
}
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken)
{
if (count > buffer.Length)
throw new ArgumentException();
while (ContentLength + count > BufferSize)
{
await Task.Delay(20, cancelToken);
if (cancelToken.IsCancellationRequested)
return;
}
//the while above assures that i cannot write past readposition with my write, so i don't have to check
// *unless its multithreaded or task is not awaited
lock (readWriteLock)
{
// if i can just write without hitting buffer.length, do it
if (WritePosition + count < BufferSize)
{
Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count);
WritePosition += count;
//Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]");
return;
}
// otherwise, i have to write to the end, then write the rest from the start
var wroteNormaly = BufferSize - WritePosition;
Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly);
//Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]");
var wroteFromStart = count - wroteNormaly;
Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart);
//Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}");
WritePosition = wroteFromStart;
}
}
}
}

View File

@ -0,0 +1,354 @@
using Discord.Audio;
using NadekoBot.Classes;
using NadekoBot.Extensions;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using VideoLibrary;
namespace NadekoBot.Modules.Music.Classes
{
public class SongInfo
{
public string Provider { get; internal set; }
public MusicType ProviderType { get; internal set; }
/// <summary>
/// Will be set only if the providertype is normal
/// </summary>
public string Query { get; internal set; }
public string Title { get; internal set; }
public string Uri { get; internal set; }
}
public class Song
{
public StreamState State { get; internal set; }
public string PrettyName =>
$"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}`";
public SongInfo SongInfo { get; }
private PoopyBuffer songBuffer { get; } = new PoopyBuffer(4.MiB());
private bool prebufferingComplete { get; set; } = false;
public MusicPlayer MusicPlayer { get; set; }
public string PrettyCurrentTime()
{
var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50);
return $"【{(int)time.TotalMinutes}m {time.Seconds}s】";
}
private ulong bytesSent { get; set; } = 0;
private Song(SongInfo songInfo)
{
this.SongInfo = songInfo;
}
private Task BufferSong(CancellationToken cancelToken) =>
Task.Factory.StartNew(async () =>
{
Process p = null;
try
{
p = Process.Start(new ProcessStartInfo
{
FileName = "ffmpeg",
Arguments = $"-i {SongInfo.Uri} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = false,
CreateNoWindow = true,
});
const int blockSize = 3840;
var buffer = new byte[blockSize];
var attempt = 0;
while (!cancelToken.IsCancellationRequested)
{
var read = 0;
try
{
read = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, blockSize, cancelToken);
}
catch
{
return;
}
if (read == 0)
if (attempt++ == 50)
break;
else
await Task.Delay(100, cancelToken);
else
attempt = 0;
await songBuffer.WriteAsync(buffer, read, cancelToken);
if (songBuffer.ContentLength > 2.MB())
prebufferingComplete = true;
}
}
catch (Exception ex)
{
Console.WriteLine($"Buffering errored: {ex.Message}");
}
finally
{
Console.WriteLine($"Buffering done." + $" [{songBuffer.ContentLength}]");
if (p != null)
{
try
{
p.Kill();
}
catch { }
p.Dispose();
}
}
}, TaskCreationOptions.LongRunning);
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
{
var bufferTask = BufferSong(cancelToken).ConfigureAwait(false);
var bufferAttempts = 0;
const int waitPerAttempt = 500;
var toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9;
while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes)
{
await Task.Delay(waitPerAttempt, cancelToken);
}
cancelToken.ThrowIfCancellationRequested();
Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}");
const int blockSize = 3840;
var attempt = 0;
while (!cancelToken.IsCancellationRequested)
{
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
byte[] buffer = new byte[blockSize];
var read = songBuffer.Read(buffer, blockSize);
unchecked
{
bytesSent += (ulong)read;
}
if (read == 0)
if (attempt++ == 20)
{
voiceClient.Wait();
Console.WriteLine($"Song finished. [{songBuffer.ContentLength}]");
break;
}
else
await Task.Delay(100, cancelToken);
else
attempt = 0;
while (this.MusicPlayer.Paused)
await Task.Delay(200, cancelToken);
buffer = AdjustVolume(buffer, MusicPlayer.Volume);
voiceClient.Send(buffer, 0, read);
}
Console.WriteLine("Awiting buffer task");
await bufferTask;
Console.WriteLine("Buffer task done.");
voiceClient.Clear();
cancelToken.ThrowIfCancellationRequested();
}
//stackoverflow ftw
private static byte[] AdjustVolume(byte[] audioSamples, float volume)
{
if (Math.Abs(volume - 1.0f) < 0.01f)
return audioSamples;
var array = new byte[audioSamples.Length];
for (var i = 0; i < array.Length; i += 2)
{
// convert byte pair to int
short buf1 = audioSamples[i + 1];
short buf2 = audioSamples[i];
buf1 = (short)((buf1 & 0xff) << 8);
buf2 = (short)(buf2 & 0xff);
var res = (short)(buf1 | buf2);
res = (short)(res * volume);
// convert back
array[i] = (byte)res;
array[i + 1] = (byte)(res >> 8);
}
return array;
}
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
{
if (string.IsNullOrWhiteSpace(query))
throw new ArgumentNullException(nameof(query));
if (musicType != MusicType.Local && IsRadioLink(query))
{
musicType = MusicType.Radio;
query = await HandleStreamContainers(query) ?? query;
}
try
{
switch (musicType)
{
case MusicType.Local:
return new Song(new SongInfo
{
Uri = "\"" + Path.GetFullPath(query) + "\"",
Title = Path.GetFileNameWithoutExtension(query),
Provider = "Local File",
ProviderType = musicType,
Query = query,
});
case MusicType.Radio:
return new Song(new SongInfo
{
Uri = query,
Title = $"{query}",
Provider = "Radio Stream",
ProviderType = musicType,
Query = query
});
}
if (SoundCloud.Default.IsSoundCloudLink(query))
{
var svideo = await SoundCloud.Default.GetVideoAsync(query);
return new Song(new SongInfo
{
Title = svideo.FullName,
Provider = "SoundCloud",
Uri = svideo.StreamLink,
ProviderType = musicType,
Query = query,
});
}
var link = await SearchHelper.FindYoutubeUrlByKeywords(query);
if (link == String.Empty)
throw new OperationCanceledException("Not a valid youtube query.");
var allVideos = await Task.Factory.StartNew(async () => await YouTube.Default.GetAllVideosAsync(link)).Unwrap();
var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio);
var video = videos
.Where(v => v.AudioBitrate < 192)
.OrderByDescending(v => v.AudioBitrate)
.FirstOrDefault();
if (video == null) // do something with this error
throw new Exception("Could not load any video elements based on the query.");
return new Song(new SongInfo
{
Title = video.Title.Substring(0, video.Title.Length - 10), // removing trailing "- You Tube"
Provider = "YouTube",
Uri = video.Uri,
Query = link,
ProviderType = musicType,
});
}
catch (Exception ex)
{
Console.WriteLine($"Failed resolving the link.{ex.Message}");
return null;
}
}
private static async Task<string> HandleStreamContainers(string query)
{
string file = null;
try
{
file = await SearchHelper.GetResponseStringAsync(query);
}
catch
{
return query;
}
if (query.Contains(".pls"))
{
//File1=http://armitunes.com:8000/
//Regex.Match(query)
try
{
var m = Regex.Match(file, "File1=(?<url>.*?)\\n");
var res = m.Groups["url"]?.ToString();
return res?.Trim();
}
catch
{
Console.WriteLine($"Failed reading .pls:\n{file}");
return null;
}
}
if (query.Contains(".m3u"))
{
/*
# This is a comment
C:\xxx4xx\xxxxxx3x\xx2xxxx\xx.mp3
C:\xxx5xx\x6xxxxxx\x7xxxxx\xx.mp3
*/
try
{
var m = Regex.Match(file, "(?<url>^[^#].*)", RegexOptions.Multiline);
var res = m.Groups["url"]?.ToString();
return res?.Trim();
}
catch
{
Console.WriteLine($"Failed reading .m3u:\n{file}");
return null;
}
}
if (query.Contains(".asx"))
{
//<ref href="http://armitunes.com:8000"/>
try
{
var m = Regex.Match(file, "<ref href=\"(?<url>.*?)\"");
var res = m.Groups["url"]?.ToString();
return res?.Trim();
}
catch
{
Console.WriteLine($"Failed reading .asx:\n{file}");
return null;
}
}
if (query.Contains(".xspf"))
{
/*
<?xml version="1.0" encoding="UTF-8"?>
<playlist version="1" xmlns="http://xspf.org/ns/0/">
<trackList>
<track><location>file:///mp3s/song_1.mp3</location></track>
*/
try
{
var m = Regex.Match(file, "<location>(?<url>.*?)</location>");
var res = m.Groups["url"]?.ToString();
return res?.Trim();
}
catch
{
Console.WriteLine($"Failed reading .xspf:\n{file}");
return null;
}
}
return query;
}
private static bool IsRadioLink(string query) =>
(query.StartsWith("http") ||
query.StartsWith("ww"))
&&
(query.Contains(".pls") ||
query.Contains(".m3u") ||
query.Contains(".asx") ||
query.Contains(".xspf"));
}
}

View File

@ -0,0 +1,107 @@
using NadekoBot.Classes;
using System;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Music.Classes
{
public class SoundCloud
{
private static readonly SoundCloud _instance = new SoundCloud();
public static SoundCloud Default => _instance;
static SoundCloud() { }
public SoundCloud() { }
public async Task<SoundCloudVideo> GetVideoAsync(string url)
{
if (string.IsNullOrWhiteSpace(url))
throw new ArgumentNullException(nameof(url));
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.SoundCloudClientID))
throw new ArgumentNullException(nameof(NadekoBot.Creds.SoundCloudClientID));
var response = await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={NadekoBot.Creds.SoundCloudClientID}");
var responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<SoundCloudVideo>(response);
if (responseObj?.Kind != "track")
throw new InvalidOperationException("Url is either not a track, or it doesn't exist.");
return responseObj;
}
public bool IsSoundCloudLink(string url) =>
System.Text.RegularExpressions.Regex.IsMatch(url, "(.*)(soundcloud.com|snd.sc)(.*)");
}
public class SoundCloudVideo
{
public string Kind = "";
public long Id = 0;
public SoundCloudUser User = new SoundCloudUser();
public string Title = "";
public string FullName => User.Name + " - " + Title;
public bool Streamable = false;
public string StreamLink => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={NadekoBot.Creds.SoundCloudClientID}";
}
public class SoundCloudUser
{
[Newtonsoft.Json.JsonProperty("username")]
public string Name;
}
/*
{"kind":"track",
"id":238888167,
"created_at":"2015/12/24 01:04:52 +0000",
"user_id":43141975,
"duration":120852,
"commentable":true,
"state":"finished",
"original_content_size":4834829,
"last_modified":"2015/12/24 01:17:59 +0000",
"sharing":"public",
"tag_list":"Funky",
"permalink":"18-fd",
"streamable":true,
"embeddable_by":"all",
"downloadable":false,
"purchase_url":null,
"label_id":null,
"purchase_title":null,
"genre":"Disco",
"title":"18 Ж",
"description":"",
"label_name":null,
"release":null,
"track_type":null,
"key_signature":null,
"isrc":null,
"video_url":null,
"bpm":null,
"release_year":null,
"release_month":null,
"release_day":null,
"original_format":"mp3",
"license":"all-rights-reserved",
"uri":"https://api.soundcloud.com/tracks/238888167",
"user":{
"id":43141975,
"kind":"user",
"permalink":"mrb00gi",
"username":"Mrb00gi",
"last_modified":"2015/12/01 16:06:57 +0000",
"uri":"https://api.soundcloud.com/users/43141975",
"permalink_url":"http://soundcloud.com/mrb00gi",
"avatar_url":"https://a1.sndcdn.com/images/default_avatar_large.png"
},
"permalink_url":"http://soundcloud.com/mrb00gi/18-fd",
"artwork_url":null,
"waveform_url":"https://w1.sndcdn.com/gsdLfvEW1cUK_m.png",
"stream_url":"https://api.soundcloud.com/tracks/238888167/stream",
"playback_count":7,
"download_count":0,
"favoritings_count":1,
"comment_count":0,
"attachments_uri":"https://api.soundcloud.com/tracks/238888167/attachments"}
*/
}

View File

@ -1,10 +1,10 @@
using Discord;
using Discord.Commands;
using Discord.Modules;
using NadekoBot._DataModels;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Music;
using NadekoBot.Extensions;
using NadekoBot.Modules.Music.Classes;
using NadekoBot.Modules.Permissions.Classes;
using System;
using System.Collections.Concurrent;
@ -443,7 +443,7 @@ namespace NadekoBot.Modules.Music
return;
var songInfos = currentPlaylist.Select(s => new Classes._DataModels.SongInfo
var songInfos = currentPlaylist.Select(s => new _DataModels.SongInfo
{
Provider = s.SongInfo.Provider,
ProviderType = (int)s.SongInfo.ProviderType,
@ -519,7 +519,7 @@ namespace NadekoBot.Modules.Music
psi.PlaylistId == playlist.Id);
var songInfos = psis.Select(psi => DbHandler.Instance
.FindOne<Classes._DataModels.SongInfo>(si => si.Id == psi.SongInfoId));
.FindOne<_DataModels.SongInfo>(si => si.Id == psi.SongInfoId));
await e.Channel.SendMessage($"`Attempting to load {songInfos.Count()} songs`");
foreach (var si in songInfos)

View File

@ -1,7 +1,7 @@
using Discord.Commands;
using Discord.Modules;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot._DataModels;
using NadekoBot.Classes.JSONModels;
using NadekoBot.Extensions;
using NadekoBot.Modules.Permissions.Classes;