124 lines
3.5 KiB
C#
124 lines
3.5 KiB
C#
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
|
|
namespace Shoko;
|
|
|
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
|
class ProtocolAttribute : Attribute
|
|
{
|
|
public string Protocol;
|
|
public ProtocolAttribute(string proto)
|
|
{
|
|
Protocol = proto;
|
|
}
|
|
}
|
|
|
|
class ProtoHandler
|
|
{
|
|
public Tab CurrentTab;
|
|
public Uri URL;
|
|
public string MediaType;
|
|
public Stream Content;
|
|
public string Status;
|
|
public bool IsLoaded = false;
|
|
protected long _loadedBytes = 0;
|
|
public virtual long LoadedBytes => _loadedBytes;
|
|
public virtual long TotalBytes => -1;
|
|
public IEnumerable<KeyValuePair<string,IEnumerable<string>>> Headers;
|
|
public IEnumerable<KeyValuePair<string,string>> MediaTypeParams;
|
|
public MediaHandler Media;
|
|
public ProtoHandler()
|
|
{
|
|
|
|
}
|
|
public ProtoHandler(Uri url)
|
|
{
|
|
URL = url;
|
|
}
|
|
public virtual Task Load()
|
|
{
|
|
Content = new MemoryStream(Encoding.UTF8.GetBytes("error: no handler for this scheme"));
|
|
MediaType = "text/plain";
|
|
OnLoaded();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public async Task<MemoryStream> Download(Stream stream, Action<long> progress)
|
|
{
|
|
var ret = new MemoryStream();
|
|
var buf = new byte[81920];
|
|
long totalBytes = 0;
|
|
int bytesRead;
|
|
while ((bytesRead = await stream.ReadAsync(buf, 0, buf.Length)) != 0) {
|
|
await ret.WriteAsync(buf.AsMemory(0, bytesRead));
|
|
totalBytes += bytesRead;
|
|
progress(totalBytes);
|
|
}
|
|
ret.Position = 0;
|
|
return ret;
|
|
}
|
|
|
|
public async Task<MemoryStream> Download(Stream stream)
|
|
{
|
|
return await Download(stream, b=>_loadedBytes=b);
|
|
}
|
|
|
|
|
|
public virtual void OnLoaded()
|
|
{
|
|
Media = MediaHandler.GetHandler(this);
|
|
IsLoaded = true;
|
|
Media.Load();
|
|
}
|
|
|
|
public virtual void Render()
|
|
{
|
|
Gui.Button("Open with external program", ()=>{
|
|
try
|
|
{
|
|
if(OperatingSystem.IsLinux())
|
|
Process.Start("xdg-open", URL.ToString());
|
|
else if(OperatingSystem.IsMacOS())
|
|
Process.Start("open", URL.ToString());
|
|
else if(OperatingSystem.IsWindows())
|
|
Process.Start(URL.ToString());
|
|
}
|
|
catch{}
|
|
});
|
|
}
|
|
|
|
public virtual void MenuBar()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the appropriate protocol handler for the URL
|
|
/// </summary>
|
|
/// <param name="url"></param>
|
|
/// <returns></returns>
|
|
public static ProtoHandler GetHandler(Uri url)
|
|
{
|
|
var proto = new UriBuilder(url).Scheme;
|
|
var type = Assembly.GetAssembly(typeof(ProtoHandler)).GetTypes()
|
|
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(ProtoHandler)) && t.GetCustomAttributes<ProtocolAttribute>().Any(x => x.Protocol == proto))
|
|
.SingleOrDefault(typeof(ProtoHandler));
|
|
return (ProtoHandler)Activator.CreateInstance(type, url);
|
|
}
|
|
|
|
public static ProtoHandler GetHandler(string url)
|
|
{
|
|
return GetHandler(new Uri(url));
|
|
}
|
|
|
|
public static string[] SupportedProtos
|
|
{
|
|
get
|
|
{
|
|
return Assembly.GetAssembly(typeof(ProtoHandler)).GetTypes()
|
|
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(ProtoHandler)))
|
|
.SelectMany(t => t.GetCustomAttributes<ProtocolAttribute>().Select(x => x.Protocol))
|
|
.ToArray();
|
|
}
|
|
}
|
|
} |