mirror of
https://github.com/QL-Win/QuickLook.git
synced 2026-05-07 02:00:21 +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 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()
|
||||
{
|
||||
@@ -32,26 +38,29 @@ public sealed class Plugin : IViewer
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return false;
|
||||
#pragma warning disable CS0162 // Unreachable code detected
|
||||
return !Directory.Exists(path)
|
||||
&& Path.GetExtension(path).Equals(".chm", StringComparison.OrdinalIgnoreCase);
|
||||
#pragma warning restore CS0162 // Unreachable code detected
|
||||
}
|
||||
|
||||
public void Prepare(string path, ContextObject context)
|
||||
{
|
||||
context.Title = Path.GetFileName(path);
|
||||
context.IsBlocked = true;
|
||||
context.PreferredSize = new Size { Width = 800, Height = 600 };
|
||||
context.PreferredSize = new Size(1280, 720);
|
||||
}
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
{
|
||||
_panel = new ChmWebpagePanel();
|
||||
_panel.PreviewCompiledHtmlHelp(path);
|
||||
|
||||
context.ViewerContent = _panel;
|
||||
context.Title = Path.GetFileName(path);
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
_panel?.Dispose();
|
||||
_panel = null;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,21 @@
|
||||
<Name>QuickLook.Common</Name>
|
||||
<Private>False</Private>
|
||||
</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>
|
||||
|
||||
</Project>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user