Removed module projects because it can't work like that atm. Commented out package commands.
This commit is contained in:
@ -0,0 +1,11 @@
|
||||
using NadekoBot.Modules.Music.Common.SongResolver.Strategies;
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver
|
||||
{
|
||||
public interface ISongResolverFactory
|
||||
{
|
||||
Task<IResolveStrategy> GetResolveStrategy(string query, MusicType? musicType);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using NadekoBot.Core.Services.Impl;
|
||||
using NadekoBot.Modules.Music.Common.SongResolver.Strategies;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver
|
||||
{
|
||||
public class SongResolverFactory : ISongResolverFactory
|
||||
{
|
||||
private readonly SoundCloudApiService _sc;
|
||||
|
||||
public SongResolverFactory(SoundCloudApiService sc)
|
||||
{
|
||||
_sc = sc;
|
||||
}
|
||||
|
||||
public async Task<IResolveStrategy> GetResolveStrategy(string query, MusicType? musicType)
|
||||
{
|
||||
await Task.Yield(); //for async warning
|
||||
switch (musicType)
|
||||
{
|
||||
case MusicType.YouTube:
|
||||
return new YoutubeResolveStrategy();
|
||||
case MusicType.Radio:
|
||||
return new RadioResolveStrategy();
|
||||
case MusicType.Local:
|
||||
return new LocalSongResolveStrategy();
|
||||
case MusicType.Soundcloud:
|
||||
return new SoundcloudResolveStrategy(_sc);
|
||||
default:
|
||||
if (_sc.IsSoundCloudLink(query))
|
||||
return new SoundcloudResolveStrategy(_sc);
|
||||
else if (RadioResolveStrategy.IsRadioLink(query))
|
||||
return new RadioResolveStrategy();
|
||||
// maybe add a check for local files in the future
|
||||
else
|
||||
return new YoutubeResolveStrategy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver.Strategies
|
||||
{
|
||||
public interface IResolveStrategy
|
||||
{
|
||||
Task<SongInfo> ResolveSong(string query);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver.Strategies
|
||||
{
|
||||
public class LocalSongResolveStrategy : IResolveStrategy
|
||||
{
|
||||
public Task<SongInfo> ResolveSong(string query)
|
||||
{
|
||||
return Task.FromResult(new SongInfo
|
||||
{
|
||||
Uri = () => Task.FromResult("\"" + Path.GetFullPath(query) + "\""),
|
||||
Title = Path.GetFileNameWithoutExtension(query),
|
||||
Provider = "Local File",
|
||||
ProviderType = MusicType.Local,
|
||||
Query = query,
|
||||
Thumbnail = "https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver.Strategies
|
||||
{
|
||||
public class RadioResolveStrategy : IResolveStrategy
|
||||
{
|
||||
private readonly Regex plsRegex = new Regex("File1=(?<url>.*?)\\n", RegexOptions.Compiled);
|
||||
private readonly Regex m3uRegex = new Regex("(?<url>^[^#].*)", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
private readonly Regex asxRegex = new Regex("<ref href=\"(?<url>.*?)\"", RegexOptions.Compiled);
|
||||
private readonly Regex xspfRegex = new Regex("<location>(?<url>.*?)</location>", RegexOptions.Compiled);
|
||||
private readonly Logger _log;
|
||||
|
||||
public RadioResolveStrategy()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
public async Task<SongInfo> ResolveSong(string query)
|
||||
{
|
||||
if (IsRadioLink(query))
|
||||
query = await HandleStreamContainers(query);
|
||||
|
||||
return new SongInfo
|
||||
{
|
||||
Uri = () => Task.FromResult(query),
|
||||
Title = query,
|
||||
Provider = "Radio Stream",
|
||||
ProviderType = MusicType.Radio,
|
||||
Query = query,
|
||||
TotalTime = TimeSpan.MaxValue,
|
||||
Thumbnail = "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png",
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsRadioLink(string query) =>
|
||||
(query.StartsWith("http") ||
|
||||
query.StartsWith("ww"))
|
||||
&&
|
||||
(query.Contains(".pls") ||
|
||||
query.Contains(".m3u") ||
|
||||
query.Contains(".asx") ||
|
||||
query.Contains(".xspf"));
|
||||
|
||||
private async Task<string> HandleStreamContainers(string query)
|
||||
{
|
||||
string file = null;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
file = await http.GetStringAsync(query).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return query;
|
||||
}
|
||||
if (query.Contains(".pls"))
|
||||
{
|
||||
//File1=http://armitunes.com:8000/
|
||||
//Regex.Match(query)
|
||||
try
|
||||
{
|
||||
var m = plsRegex.Match(file);
|
||||
var res = m.Groups["url"]?.ToString();
|
||||
return res?.Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn($"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 = m3uRegex.Match(file);
|
||||
var res = m.Groups["url"]?.ToString();
|
||||
return res?.Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn($"Failed reading .m3u:\n{file}");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
if (query.Contains(".asx"))
|
||||
{
|
||||
//<ref href="http://armitunes.com:8000"/>
|
||||
try
|
||||
{
|
||||
var m = asxRegex.Match(file);
|
||||
var res = m.Groups["url"]?.ToString();
|
||||
return res?.Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn($"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 = xspfRegex.Match(file);
|
||||
var res = m.Groups["url"]?.ToString();
|
||||
return res?.Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn($"Failed reading .xspf:\n{file}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
using NadekoBot.Modules.Music.Extensions;
|
||||
using NadekoBot.Core.Services.Impl;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver.Strategies
|
||||
{
|
||||
public class SoundcloudResolveStrategy : IResolveStrategy
|
||||
{
|
||||
private readonly SoundCloudApiService _sc;
|
||||
|
||||
public SoundcloudResolveStrategy(SoundCloudApiService sc)
|
||||
{
|
||||
_sc = sc;
|
||||
}
|
||||
|
||||
public async Task<SongInfo> ResolveSong(string query)
|
||||
{
|
||||
var svideo = !_sc.IsSoundCloudLink(query) ?
|
||||
await _sc.GetVideoByQueryAsync(query).ConfigureAwait(false) :
|
||||
await _sc.ResolveVideoAsync(query).ConfigureAwait(false);
|
||||
|
||||
if (svideo == null)
|
||||
return null;
|
||||
return await svideo.GetSongInfo();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using NadekoBot.Core.Services.Impl;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common.SongResolver.Strategies
|
||||
{
|
||||
public class YoutubeResolveStrategy : IResolveStrategy
|
||||
{
|
||||
private readonly Logger _log;
|
||||
|
||||
public YoutubeResolveStrategy()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
public async Task<SongInfo> ResolveSong(string query)
|
||||
{
|
||||
_log.Info("Getting link");
|
||||
string[] data;
|
||||
try
|
||||
{
|
||||
using (var ytdl = new YtdlOperation())
|
||||
{
|
||||
data = (await ytdl.GetDataAsync(query)).Split('\n');
|
||||
}
|
||||
if (data.Length < 6)
|
||||
{
|
||||
_log.Info("No song found. Data less than 6");
|
||||
return null;
|
||||
}
|
||||
TimeSpan time;
|
||||
if (!TimeSpan.TryParseExact(data[4], new[] { "ss", "m\\:ss", "mm\\:ss", "h\\:mm\\:ss", "hh\\:mm\\:ss", "hhh\\:mm\\:ss" }, CultureInfo.InvariantCulture, out time))
|
||||
time = TimeSpan.FromHours(24);
|
||||
|
||||
return new SongInfo()
|
||||
{
|
||||
Title = data[0],
|
||||
VideoId = data[1],
|
||||
Uri = async () =>
|
||||
{
|
||||
using (var ytdl = new YtdlOperation())
|
||||
{
|
||||
data = (await ytdl.GetDataAsync(query)).Split('\n');
|
||||
}
|
||||
if (data.Length < 6)
|
||||
{
|
||||
_log.Info("No song found. Data less than 6");
|
||||
return null;
|
||||
}
|
||||
return data[2];
|
||||
},
|
||||
Thumbnail = data[3],
|
||||
TotalTime = time,
|
||||
Provider = "YouTube",
|
||||
ProviderType = MusicType.YouTube,
|
||||
Query = "https://youtube.com/watch?v=" + data[1],
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user