mirror of
https://github.com/QL-Win/QuickLook.git
synced 2026-05-16 01:08:03 +08:00
Add CHM viewer plugin (WebView2-based)
This commit does not implement the file link
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
# Ignore HTML files in Resources and subdirectories
|
||||||
|
Resources/**/*.html linguist-vendored
|
||||||
|
|
||||||
|
# Ignore CSS files in Resources and subdirectories
|
||||||
|
Resources/**/*.css linguist-vendored
|
||||||
|
|
||||||
|
# Ignore JS files in Resources and subdirectories
|
||||||
|
Resources/**/*.js linguist-vendored
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
// Copyright © 2017-2026 QL-Win Contributors
|
||||||
|
//
|
||||||
|
// This file is part of QuickLook program.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using QuickLook.Plugin.HtmlViewer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.ChmViewer;
|
||||||
|
|
||||||
|
public class ChmWebpagePanel : WebpagePanel
|
||||||
|
{
|
||||||
|
private const string _resourcePrefix = "QuickLook.Plugin.ChmViewer.Resources.";
|
||||||
|
private static readonly Dictionary<string, byte[]> _resources = [];
|
||||||
|
private readonly byte[] _homePage;
|
||||||
|
|
||||||
|
static ChmWebpagePanel()
|
||||||
|
{
|
||||||
|
InitializeResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChmWebpagePanel()
|
||||||
|
{
|
||||||
|
_homePage = ReadResource("/chm2html.html") ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InitializeResources()
|
||||||
|
{
|
||||||
|
if (_resources.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
foreach (var resourceName in assembly.GetManifestResourceNames())
|
||||||
|
{
|
||||||
|
if (!resourceName.StartsWith(_resourcePrefix, StringComparison.Ordinal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var relativePath = resourceName.Substring(_resourcePrefix.Length).Replace('\\', '/');
|
||||||
|
if (string.IsNullOrEmpty(relativePath))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||||
|
if (stream == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
using var memoryStream = new MemoryStream();
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
_resources[$"/{relativePath}"] = memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PreviewCompiledHtmlHelp(string path)
|
||||||
|
{
|
||||||
|
FallbackPath = Path.GetDirectoryName(path);
|
||||||
|
|
||||||
|
var chmFileUrl = Helper.FilePathToFileUrl(path);
|
||||||
|
var pluginUri = new Uri($"file://quicklook/?plugin=1&chm={Uri.EscapeDataString(chmFileUrl.AbsoluteUri)}");
|
||||||
|
|
||||||
|
NavigateToUri(pluginUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void WebView_WebResourceRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2WebResourceRequestedEventArgs args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(args.Request.Uri))
|
||||||
|
{
|
||||||
|
base.WebView_WebResourceRequested(sender, args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestedUri = new Uri(args.Request.Uri);
|
||||||
|
if (requestedUri.Scheme != "file")
|
||||||
|
{
|
||||||
|
base.WebView_WebResourceRequested(sender, args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestedPath = Uri.UnescapeDataString(requestedUri.AbsolutePath);
|
||||||
|
if (requestedPath == "/")
|
||||||
|
{
|
||||||
|
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
|
||||||
|
new MemoryStream(_homePage), 200, "OK", MimeTypes.GetContentType(".html"));
|
||||||
|
args.Response = response;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContainsKey(requestedPath))
|
||||||
|
{
|
||||||
|
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
|
||||||
|
ReadStream(requestedPath), 200, "OK", MimeTypes.GetContentType(Path.GetExtension(requestedPath)));
|
||||||
|
args.Response = response;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.WebView_WebResourceRequested(sender, args);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
base.WebView_WebResourceRequested(sender, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ContainsKey(string key) => _resources.ContainsKey(key);
|
||||||
|
|
||||||
|
private static Stream ReadStream(string key) => new MemoryStream(_resources[key]);
|
||||||
|
|
||||||
|
private static byte[] ReadResource(string key) => _resources.TryGetValue(key, out var value) ? value : null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright © 2017-2026 QL-Win Contributors
|
||||||
|
//
|
||||||
|
// This file is part of QuickLook program.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.ChmViewer;
|
||||||
|
|
||||||
|
internal static class Helper
|
||||||
|
{
|
||||||
|
public static Uri FilePathToFileUrl(string filePath)
|
||||||
|
{
|
||||||
|
var uri = new StringBuilder();
|
||||||
|
foreach (var v in filePath)
|
||||||
|
if (v >= 'a' && v <= 'z' || v >= 'A' && v <= 'Z' || v >= '0' && v <= '9' ||
|
||||||
|
v == '+' || v == '/' || v == ':' || v == '.' || v == '-' || v == '_' || v == '~' ||
|
||||||
|
v > '\x80')
|
||||||
|
uri.Append(v);
|
||||||
|
else if (v == Path.DirectorySeparatorChar || v == Path.AltDirectorySeparatorChar)
|
||||||
|
uri.Append('/');
|
||||||
|
else
|
||||||
|
uri.Append($"%{(int)v:X2}");
|
||||||
|
if (uri.Length >= 2 && uri[0] == '/' && uri[1] == '/') // UNC path - Universal Naming Convention
|
||||||
|
uri.Insert(0, "file:");
|
||||||
|
else
|
||||||
|
uri.Insert(0, "file:///");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new Uri(uri.ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,13 @@ namespace QuickLook.Plugin.ChmViewer;
|
|||||||
|
|
||||||
public sealed class Plugin : IViewer
|
public sealed class Plugin : IViewer
|
||||||
{
|
{
|
||||||
public int Priority => 0;
|
private ChmWebpagePanel _panel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The implementation of this plugin is better than following
|
||||||
|
/// https://github.com/emako/QuickLook.Plugin.SumatraPDFReader
|
||||||
|
/// </summary>
|
||||||
|
public int Priority => 2;
|
||||||
|
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
@@ -32,26 +38,29 @@ public sealed class Plugin : IViewer
|
|||||||
|
|
||||||
public bool CanHandle(string path)
|
public bool CanHandle(string path)
|
||||||
{
|
{
|
||||||
return false;
|
|
||||||
#pragma warning disable CS0162 // Unreachable code detected
|
|
||||||
return !Directory.Exists(path)
|
return !Directory.Exists(path)
|
||||||
&& Path.GetExtension(path).Equals(".chm", StringComparison.OrdinalIgnoreCase);
|
&& Path.GetExtension(path).Equals(".chm", StringComparison.OrdinalIgnoreCase);
|
||||||
#pragma warning restore CS0162 // Unreachable code detected
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ContextObject context)
|
public void Prepare(string path, ContextObject context)
|
||||||
{
|
{
|
||||||
context.Title = Path.GetFileName(path);
|
context.PreferredSize = new Size(1280, 720);
|
||||||
context.IsBlocked = true;
|
|
||||||
context.PreferredSize = new Size { Width = 800, Height = 600 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ContextObject context)
|
public void View(string path, ContextObject context)
|
||||||
{
|
{
|
||||||
|
_panel = new ChmWebpagePanel();
|
||||||
|
_panel.PreviewCompiledHtmlHelp(path);
|
||||||
|
|
||||||
|
context.ViewerContent = _panel;
|
||||||
|
context.Title = Path.GetFileName(path);
|
||||||
context.IsBusy = false;
|
context.IsBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cleanup()
|
public void Cleanup()
|
||||||
{
|
{
|
||||||
|
_panel?.Dispose();
|
||||||
|
_panel = null;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,21 @@
|
|||||||
<Name>QuickLook.Common</Name>
|
<Name>QuickLook.Common</Name>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\QuickLook.Plugin.HtmlViewer\QuickLook.Plugin.HtmlViewer.csproj">
|
||||||
|
<Project>{CE22A1F3-7F2C-4EC8-BFDE-B58D0EB625FC}</Project>
|
||||||
|
<Name>QuickLook.Plugin.HtmlViewer</Name>
|
||||||
|
<Private>False</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3912.50">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Resources\chm2html.html" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user