mirror of
https://github.com/Stone-Red-Code/Markdowser.git
synced 2026-09-08 07:46:25 +02:00
implement cache attempt
This commit is contained in:
Generated
+1
@@ -0,0 +1 @@
|
|||||||
|
Markdowser
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RiderProjectSettingsUpdater">
|
||||||
|
<option name="vcsConfiguration" value="2" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AutoGeneratedRunConfigurationManager">
|
||||||
|
<projectFile>Markdowser/Markdowser.csproj</projectFile>
|
||||||
|
</component>
|
||||||
|
<component name="AutoImportSettings">
|
||||||
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="35ad98ab-fce0-4c9e-9180-ec9795d8ed8e" name="Changes" comment="" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="DpaMonitoringSettings">
|
||||||
|
<option name="autoShow" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectColorInfo"><![CDATA[{
|
||||||
|
"associatedIndex": 6
|
||||||
|
}]]></component>
|
||||||
|
<component name="ProjectId" id="2fg8GifhQMdOrTygPnNJLDd0rxo" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
|
"keyToString": {
|
||||||
|
".NET Project.Markdowser.executor": "Run",
|
||||||
|
"git-widget-placeholder": "develop",
|
||||||
|
"node.js.selected.package.tslint": "(autodetect)"
|
||||||
|
},
|
||||||
|
"keyToStringList": {
|
||||||
|
"rider.external.source.directories": [
|
||||||
|
"C:\\Users\\Camer\\AppData\\Roaming\\JetBrains\\Rider2024.1\\resharper-host\\DecompilerCache",
|
||||||
|
"C:\\Users\\Camer\\AppData\\Roaming\\JetBrains\\Rider2024.1\\resharper-host\\SourcesCache",
|
||||||
|
"C:\\Users\\Camer\\AppData\\Local\\Symbols\\src"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}]]></component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration name="Markdowser" type="DotNetProject" factoryName=".NET Project" temporary="true">
|
||||||
|
<option name="EXE_PATH" value="$PROJECT_DIR$/Markdowser/bin/Debug/net8.0/Markdowser.exe" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Markdowser/bin/Debug/net8.0" />
|
||||||
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
|
<option name="USE_MONO" value="0" />
|
||||||
|
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||||
|
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Markdowser/Markdowser.csproj" />
|
||||||
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
|
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||||
|
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||||
|
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||||
|
<option name="PROJECT_TFM" value="net8.0" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Build" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<recent_temporary>
|
||||||
|
<list>
|
||||||
|
<item itemvalue=".NET Project.Markdowser" />
|
||||||
|
</list>
|
||||||
|
</recent_temporary>
|
||||||
|
</component>
|
||||||
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
|
<component name="TaskManager">
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using Markdowser.ViewModels;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Markdowser.Utilities
|
||||||
|
{
|
||||||
|
namespace Markdowser.Utilities
|
||||||
|
{
|
||||||
|
public class CacheService
|
||||||
|
{
|
||||||
|
private Dictionary<string, ContentViewModelBase> cache = new Dictionary<string, ContentViewModelBase>();
|
||||||
|
|
||||||
|
public ContentViewModelBase Get(string url)
|
||||||
|
{
|
||||||
|
if (cache.ContainsKey(url))
|
||||||
|
{
|
||||||
|
return cache[url];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(string url, ContentViewModelBase content)
|
||||||
|
{
|
||||||
|
cache[url] = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ using Markdowser.Models;
|
|||||||
using Markdowser.Processing;
|
using Markdowser.Processing;
|
||||||
using Markdowser.Processing.Processors;
|
using Markdowser.Processing.Processors;
|
||||||
using Markdowser.Utilities;
|
using Markdowser.Utilities;
|
||||||
|
using Markdowser.Utilities.Markdowser.Utilities;
|
||||||
using Markdowser.ViewModels.Content;
|
using Markdowser.ViewModels.Content;
|
||||||
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@@ -26,6 +27,7 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly HttpClient httpClient = new(new HttpClientHandler() { AllowAutoRedirect = true });
|
private readonly HttpClient httpClient = new(new HttpClientHandler() { AllowAutoRedirect = true });
|
||||||
private readonly ContentProcessorManager contentProcessorManager = new();
|
private readonly ContentProcessorManager contentProcessorManager = new();
|
||||||
|
private readonly CacheService cacheService = new CacheService();
|
||||||
|
|
||||||
private ContentViewModelBase content;
|
private ContentViewModelBase content;
|
||||||
private TabItem currentTab = null!;
|
private TabItem currentTab = null!;
|
||||||
@@ -196,50 +198,57 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
return Uri.TryCreate(uriString, UriKind.Absolute, out uri) && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);
|
return Uri.TryCreate(uriString, UriKind.Absolute, out uri) && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FetchUrl()
|
private void FetchUrl()
|
||||||
|
{
|
||||||
|
if (IsBusy)
|
||||||
{
|
{
|
||||||
if (IsBusy)
|
WindowNotificationManager.Show(new Notification("Busy", "The browser is currently busy.", NotificationType.Warning));
|
||||||
{
|
return;
|
||||||
WindowNotificationManager.Show(new Notification("Busy", "The browser is currently busy.", NotificationType.Warning));
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(Url))
|
if (string.IsNullOrWhiteSpace(Url))
|
||||||
{
|
{
|
||||||
Content = DefaultContent;
|
Content = DefaultContent;
|
||||||
Debug.WriteLine("URL is empty.");
|
Debug.WriteLine("URL is empty.");
|
||||||
CurrentTab.Header = "New Tab";
|
CurrentTab.Header = "New Tab";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidHttpUri(Url, out _))
|
if (!IsValidHttpUri(Url, out _))
|
||||||
|
{
|
||||||
|
if (Url.StartsWith("//"))
|
||||||
{
|
{
|
||||||
if (Url.StartsWith("//"))
|
Url = $"https:{Url}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Search with duckduckgo
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Url = $"https:{Url}";
|
Url = string.Format(Settings.Current.SearchEngineUrl, Uri.EscapeDataString(Url));
|
||||||
|
}
|
||||||
|
catch (FormatException ex)
|
||||||
|
{
|
||||||
|
WindowNotificationManager.Show(new Notification("Invalid Search Engine URL", $"{ex.Message}", NotificationType.Error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IsBusy = true;
|
||||||
|
Progress = 0;
|
||||||
|
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Fetching URL...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ContentViewModelBase cachedContent = cacheService.Get(Url);
|
||||||
|
if (cachedContent != null)
|
||||||
|
{
|
||||||
|
Content = cachedContent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// Search with duckduckgo
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Url = string.Format(Settings.Current.SearchEngineUrl, Uri.EscapeDataString(Url));
|
|
||||||
}
|
|
||||||
catch (FormatException ex)
|
|
||||||
{
|
|
||||||
WindowNotificationManager.Show(new Notification("Invalid Search Engine URL", $"{ex.Message}", NotificationType.Error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IsBusy = true;
|
|
||||||
Progress = 0;
|
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
Debug.WriteLine("Fetching URL...");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
HttpResponseMessage httpResponseMessage = await httpClient.GetAsync(Url);
|
HttpResponseMessage httpResponseMessage = await httpClient.GetAsync(Url);
|
||||||
|
|
||||||
@@ -266,42 +275,44 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
Content = await contentProcessorManager.ProcessContent(httpResponseMessage, new Progress<ProcessingProgress>(p => Progress = p.Percentage));
|
Content = await contentProcessorManager.ProcessContent(httpResponseMessage, new Progress<ProcessingProgress>(p => Progress = p.Percentage));
|
||||||
|
cacheService.Set(Url, Content);
|
||||||
Dispatcher.UIThread.Post(() => CurrentTab.Header = Content.Title);
|
|
||||||
}
|
}
|
||||||
catch (HttpRequestException e)
|
|
||||||
|
Dispatcher.UIThread.Post(() => CurrentTab.Header = Content.Title);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException e)
|
||||||
|
{
|
||||||
|
StringBuilder errorMessage = new();
|
||||||
|
|
||||||
|
if (e.StatusCode is not null)
|
||||||
{
|
{
|
||||||
StringBuilder errorMessage = new();
|
_ = errorMessage.AppendLine($"# {(int)e.StatusCode} {e.StatusCode}");
|
||||||
|
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {(int)e.StatusCode} {e.StatusCode}");
|
||||||
if (e.StatusCode is not null)
|
|
||||||
{
|
|
||||||
_ = errorMessage.AppendLine($"# {(int)e.StatusCode} {e.StatusCode}");
|
|
||||||
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {(int)e.StatusCode} {e.StatusCode}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {e.GetType().Name}");
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = errorMessage.AppendLine($"# {e.HttpRequestError}");
|
|
||||||
_ = errorMessage.AppendLine($"Failed to fetch URL: {e.Message}");
|
|
||||||
|
|
||||||
Content = new MarkdownContentViewModel("Error", errorMessage.ToString());
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
else
|
||||||
{
|
{
|
||||||
StringBuilder errorMessage = new();
|
|
||||||
|
|
||||||
_ = errorMessage.AppendLine($"# {e.GetType().Name}");
|
|
||||||
_ = errorMessage.AppendLine($"Failed to fetch URL: {e.Message}");
|
|
||||||
|
|
||||||
Content = new MarkdownContentViewModel("Error", errorMessage.ToString());
|
|
||||||
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {e.GetType().Name}");
|
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {e.GetType().Name}");
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
_ = errorMessage.AppendLine($"# {e.HttpRequestError}");
|
||||||
IsBusy = false;
|
_ = errorMessage.AppendLine($"Failed to fetch URL: {e.Message}");
|
||||||
}
|
|
||||||
});
|
Content = new MarkdownContentViewModel("Error", errorMessage.ToString());
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
StringBuilder errorMessage = new();
|
||||||
|
|
||||||
|
_ = errorMessage.AppendLine($"# {e.GetType().Name}");
|
||||||
|
_ = errorMessage.AppendLine($"Failed to fetch URL: {e.Message}");
|
||||||
|
|
||||||
|
Content = new MarkdownContentViewModel("Error", errorMessage.ToString());
|
||||||
|
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {e.GetType().Name}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
xmlns:md="https://github.com/whistyun/Markdown.Avalonia"
|
xmlns:md="https://github.com/whistyun/Markdown.Avalonia"
|
||||||
xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
|
xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
|
||||||
x:DataType="vm:Content.CommonImageContentViewModel"
|
xmlns:content="clr-namespace:Markdowser.ViewModels.Content"
|
||||||
|
x:DataType="content:CommonImageContentViewModel"
|
||||||
x:Class="Markdowser.Views.Content.CommonImageContentView">
|
x:Class="Markdowser.Views.Content.CommonImageContentView">
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
xmlns:md="https://github.com/whistyun/Markdown.Avalonia"
|
xmlns:md="https://github.com/whistyun/Markdown.Avalonia"
|
||||||
xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
|
xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
|
||||||
x:DataType="vm:Content.MarkdownContentViewModel"
|
xmlns:content="clr-namespace:Markdowser.ViewModels.Content"
|
||||||
|
x:DataType="content:MarkdownContentViewModel"
|
||||||
x:Class="Markdowser.Views.Content.MarkdownContentView">
|
x:Class="Markdowser.Views.Content.MarkdownContentView">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user