mirror of
https://github.com/Stone-Red-Code/Markdowser.git
synced 2026-09-04 09:06:15 +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.Processors;
|
||||
using Markdowser.Utilities;
|
||||
using Markdowser.Utilities.Markdowser.Utilities;
|
||||
using Markdowser.ViewModels.Content;
|
||||
|
||||
using ReactiveUI;
|
||||
@@ -26,6 +27,7 @@ public partial class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
private readonly HttpClient httpClient = new(new HttpClientHandler() { AllowAutoRedirect = true });
|
||||
private readonly ContentProcessorManager contentProcessorManager = new();
|
||||
private readonly CacheService cacheService = new CacheService();
|
||||
|
||||
private ContentViewModelBase content;
|
||||
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);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
Content = DefaultContent;
|
||||
Debug.WriteLine("URL is empty.");
|
||||
CurrentTab.Header = "New Tab";
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Url))
|
||||
{
|
||||
Content = DefaultContent;
|
||||
Debug.WriteLine("URL is empty.");
|
||||
CurrentTab.Header = "New Tab";
|
||||
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
|
||||
{
|
||||
// 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);
|
||||
|
||||
@@ -266,42 +275,44 @@ public partial class MainWindowViewModel : ViewModelBase
|
||||
}
|
||||
|
||||
Content = await contentProcessorManager.ProcessContent(httpResponseMessage, new Progress<ProcessingProgress>(p => Progress = p.Percentage));
|
||||
|
||||
Dispatcher.UIThread.Post(() => CurrentTab.Header = Content.Title);
|
||||
cacheService.Set(Url, Content);
|
||||
}
|
||||
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();
|
||||
|
||||
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());
|
||||
_ = errorMessage.AppendLine($"# {(int)e.StatusCode} {e.StatusCode}");
|
||||
Dispatcher.UIThread.Post(() => CurrentTab.Header = $"Error: {(int)e.StatusCode} {e.StatusCode}");
|
||||
}
|
||||
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}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_ = errorMessage.AppendLine($"# {e.HttpRequestError}");
|
||||
_ = 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"
|
||||
xmlns:md="https://github.com/whistyun/Markdown.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">
|
||||
|
||||
<Grid>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
xmlns:md="https://github.com/whistyun/Markdown.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">
|
||||
|
||||
<UserControl.Resources>
|
||||
|
||||
Reference in New Issue
Block a user