WIP: icon database
This commit is contained in:
parent
682af23f55
commit
4dd399f537
@ -33,13 +33,12 @@ namespace FizzyLauncher
|
||||
private System.ComponentModel.IContainer components;
|
||||
|
||||
protected bool isBusy = false;
|
||||
protected string faviconAddress = null;
|
||||
|
||||
protected WebParser webParser = null;
|
||||
protected WebClient webClient = null;
|
||||
|
||||
|
||||
public BookmarkForm(BookmarkItem model) : base()
|
||||
public BookmarkForm(BookmarkItem model, Image icon) : base()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@ -47,7 +46,7 @@ namespace FizzyLauncher
|
||||
textBox2.Text = model.SiteAddress?.Trim() ?? string.Empty;
|
||||
memoBox1.Text = model.SiteDescription?.Trim() ?? string.Empty;
|
||||
memoBox2.Text = model.Notes?.Trim() ?? string.Empty;
|
||||
faviconAddress = model.FaviconAddress;
|
||||
pictureBox1.Image = icon;
|
||||
|
||||
textBox2.SetTooltipText(toolTip1, "Retrieve web page information");
|
||||
}
|
||||
@ -308,19 +307,21 @@ namespace FizzyLauncher
|
||||
}
|
||||
|
||||
|
||||
public BookmarkItem Model
|
||||
public BookmarkResult Model
|
||||
{
|
||||
get => new BookmarkItem()
|
||||
get => new BookmarkResult()
|
||||
{
|
||||
Item = new BookmarkItem()
|
||||
{
|
||||
SiteName = textBox1.Text?.Trim() ?? string.Empty,
|
||||
SiteAddress = textBox2.Text?.Trim() ?? string.Empty,
|
||||
SiteDescription = memoBox1.Text?.Trim() ?? string.Empty,
|
||||
Notes = memoBox2.Text?.Trim() ?? string.Empty,
|
||||
FaviconAddress = faviconAddress
|
||||
Notes = memoBox2.Text?.Trim() ?? string.Empty
|
||||
},
|
||||
Icon = pictureBox1.Image
|
||||
};
|
||||
}
|
||||
|
||||
public Image Favicon { get => pictureBox1.Image; }
|
||||
|
||||
protected bool IsBusy
|
||||
{
|
||||
@ -362,23 +363,25 @@ namespace FizzyLauncher
|
||||
return;
|
||||
}
|
||||
|
||||
BookmarkItem rs = webParser.RetrieveDetails(textBox2.Text);
|
||||
BookmarkResult rs = webParser.RetrieveDetails(textBox2.Text);
|
||||
if (rs == null)
|
||||
{
|
||||
IsBusy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(rs.SiteName)) ThreadControl.SetText(textBox1, rs.SiteName);
|
||||
if (!string.IsNullOrWhiteSpace(rs.SiteDescription)) ThreadControl.SetText(memoBox1, rs.SiteDescription);
|
||||
if (rs.Item == null) rs.Item = new BookmarkItem();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rs.FaviconAddress))
|
||||
if (!string.IsNullOrWhiteSpace(rs.Item.SiteName)) ThreadControl.SetText(textBox1, rs.Item.SiteName);
|
||||
if (!string.IsNullOrWhiteSpace(rs.Item.SiteDescription)) ThreadControl.SetText(memoBox1, rs.Item.SiteDescription);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rs.IconURL))
|
||||
{
|
||||
ThreadControl.Clear(pictureBox1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadControl.SetValue(pictureBox1, RetrieveImage(rs.FaviconAddress));
|
||||
ThreadControl.SetValue(pictureBox1, RetrieveImage(rs.IconURL));
|
||||
}
|
||||
|
||||
IsBusy = false;
|
||||
|
@ -142,6 +142,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.34" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.10" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.2" />
|
||||
</ItemGroup>
|
||||
|
15
Classes/BookmarkResult.cs
Normal file
15
Classes/BookmarkResult.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using bzit.bomg.Models;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BookmarkManager
|
||||
{
|
||||
public class BookmarkResult
|
||||
{
|
||||
public BookmarkItem Item { get; set; } = null;
|
||||
|
||||
public string IconURL { get; set; } = null;
|
||||
|
||||
public Image Icon { get; set; } = null;
|
||||
|
||||
}
|
||||
}
|
22
Classes/Crypto.cs
Normal file
22
Classes/Crypto.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace BookmarkManager
|
||||
{
|
||||
public class Crypto
|
||||
{
|
||||
public static string GetSHA256Hash(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text)) return string.Empty;
|
||||
|
||||
using (var sha = new SHA256Managed())
|
||||
{
|
||||
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(text));
|
||||
|
||||
return BitConverter.ToString(hash).Replace("-", string.Empty) + "+" + text.Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
244
Classes/IconDatabase.cs
Normal file
244
Classes/IconDatabase.cs
Normal file
@ -0,0 +1,244 @@
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
|
||||
namespace BookmarkManager
|
||||
{
|
||||
public class IconDatabase
|
||||
{
|
||||
protected string dbFilename = null;
|
||||
protected SqliteConnection dbConnection = null;
|
||||
|
||||
|
||||
public IconDatabase(string filename)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filename)) return;
|
||||
|
||||
dbFilename = filename;
|
||||
|
||||
bool isNew = !File.Exists(dbFilename);
|
||||
|
||||
SqliteConnectionStringBuilder builder = new SqliteConnectionStringBuilder();
|
||||
builder.DataSource = dbFilename;
|
||||
builder.Cache = SqliteCacheMode.Private;
|
||||
builder.Mode = SqliteOpenMode.ReadWriteCreate;
|
||||
|
||||
dbConnection = new SqliteConnection(builder.ToString());
|
||||
dbConnection.Open();
|
||||
|
||||
if (isNew) Initialise();
|
||||
|
||||
|
||||
|
||||
|
||||
//if (File.Exists(filename))
|
||||
//{
|
||||
// File.Delete("test.db3");
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
public bool AddIcon(string id, Image image)
|
||||
{
|
||||
if (dbConnection == null) return false;
|
||||
if (string.IsNullOrWhiteSpace(id)) return false;
|
||||
|
||||
if (image == null) return DeleteIcon(id);
|
||||
if (HasIcon(id)) return UpdateIcon(id, image);
|
||||
|
||||
SqliteCommand command = new SqliteCommand();
|
||||
command.Connection = dbConnection;
|
||||
command.CommandText = "INSERT INTO icons (id, content) VALUES (@id, @content)";
|
||||
command.Parameters.Add("@id", SqliteType.Text).Value = id;
|
||||
command.Parameters.Add("@content", SqliteType.Blob, 20).Value = ImageToBytes(image);
|
||||
|
||||
try
|
||||
{
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (dbConnection == null) return;
|
||||
|
||||
dbConnection.Close();
|
||||
dbConnection.Dispose();
|
||||
dbConnection = null;
|
||||
}
|
||||
|
||||
public bool DeleteIcon(string id)
|
||||
{
|
||||
if (dbConnection == null) return false;
|
||||
if (string.IsNullOrWhiteSpace(id)) return false;
|
||||
|
||||
SqliteCommand command = new SqliteCommand();
|
||||
command.Connection = dbConnection;
|
||||
command.CommandText = "DELETE FROM icons WHERE id = @id";
|
||||
command.Parameters.Add("@id", SqliteType.Text).Value = id;
|
||||
|
||||
try
|
||||
{
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public Image FindIcon(string id)
|
||||
{
|
||||
if (dbConnection == null) return null;
|
||||
if (string.IsNullOrWhiteSpace(id)) return null;
|
||||
|
||||
byte[] iconBytes = null;
|
||||
|
||||
SqliteCommand command = new SqliteCommand();
|
||||
command.Connection = dbConnection;
|
||||
command.CommandText = "SELECT content FROM icons WHERE @id";
|
||||
command.Parameters.Add("@id", SqliteType.Text).Value = id;
|
||||
|
||||
try
|
||||
{
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader["content"] != null && !Convert.IsDBNull(reader["content"]))
|
||||
{
|
||||
iconBytes = (byte[])reader["content"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
command.Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (iconBytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Image img = null;
|
||||
|
||||
try
|
||||
{
|
||||
img = Image.FromStream(new MemoryStream(iconBytes));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Bitmap(img, 16, 16);
|
||||
}
|
||||
|
||||
public bool HasIcon(string id)
|
||||
{
|
||||
if (dbConnection == null) return false;
|
||||
if (string.IsNullOrWhiteSpace(id)) return false;
|
||||
|
||||
int rv = 0;
|
||||
|
||||
SqliteCommand command = new SqliteCommand();
|
||||
command.Connection = dbConnection;
|
||||
command.CommandText = "SELECT COUNT(1) AS count FROM icons WHERE @id";
|
||||
command.Parameters.Add("@id", SqliteType.Text).Value = id;
|
||||
|
||||
try
|
||||
{
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader["count"] != null && !Convert.IsDBNull(reader["count"]))
|
||||
{
|
||||
rv = (int)reader["count"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
command.Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (rv > 0);
|
||||
}
|
||||
|
||||
public bool UpdateIcon(string id, Image image)
|
||||
{
|
||||
if (dbConnection == null) return false;
|
||||
if (string.IsNullOrWhiteSpace(id)) return false;
|
||||
|
||||
if (image == null) return DeleteIcon(id);
|
||||
if (!HasIcon(id)) return AddIcon(id, image);
|
||||
|
||||
SqliteCommand command = new SqliteCommand();
|
||||
command.Connection = dbConnection;
|
||||
command.CommandText = "UPDATE icons SET content = @content WHERE id = @id";
|
||||
command.Parameters.Add("@id", SqliteType.Text).Value = id;
|
||||
command.Parameters.Add("@content", SqliteType.Blob, 20).Value = ImageToBytes(image);
|
||||
|
||||
try
|
||||
{
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected bool Initialise()
|
||||
{
|
||||
if (dbConnection == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
SqliteCommand command = new SqliteCommand("CREATE TABLE icons (id TEXT PRIMARY KEY, content BLOB)", dbConnection);
|
||||
command.ExecuteNonQuery();
|
||||
command.Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected byte[] ImageToBytes(Image image)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
//image.Save(stream, ((image.RawFormat == null) ? ImageFormat.Bmp : new ImageFormat(image.RawFormat.Guid)));
|
||||
image.Save(stream, ImageFormat.Bmp);
|
||||
stream.Close();
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ namespace BookmarkManager
|
||||
protected HttpWeb webClient = null;
|
||||
|
||||
|
||||
public BookmarkItem RetrieveDetails(string url)
|
||||
public BookmarkResult RetrieveDetails(string url)
|
||||
{
|
||||
string sourceCode = retrieveSourceCode(url);
|
||||
if (string.IsNullOrWhiteSpace(sourceCode))
|
||||
@ -19,24 +19,25 @@ namespace BookmarkManager
|
||||
return null;
|
||||
}
|
||||
|
||||
BookmarkItem rs = new BookmarkItem();
|
||||
BookmarkResult rs = new BookmarkResult();
|
||||
rs.Item = new BookmarkItem();
|
||||
|
||||
HtmlDocument document = new HtmlDocument();
|
||||
document.LoadHtml(sourceCode);
|
||||
|
||||
rs.SiteName = parseSiteTitle(document);
|
||||
rs.SiteAddress = url;
|
||||
rs.SiteDescription = parseSiteDescription(document);
|
||||
rs.FaviconAddress = parseSiteIcon(document);
|
||||
rs.Item.SiteName = parseSiteTitle(document);
|
||||
rs.Item.SiteAddress = url;
|
||||
rs.Item.SiteDescription = parseSiteDescription(document);
|
||||
rs.IconURL = parseSiteIcon(document);
|
||||
|
||||
// resolve relative URL
|
||||
if (!string.IsNullOrWhiteSpace(rs.FaviconAddress))
|
||||
if (!string.IsNullOrWhiteSpace(rs.IconURL))
|
||||
{
|
||||
Uri iconAddressURI;
|
||||
bool rv = Uri.TryCreate(new Uri(url), rs.FaviconAddress, out iconAddressURI);
|
||||
bool rv = Uri.TryCreate(new Uri(url), rs.IconURL, out iconAddressURI);
|
||||
if (rv)
|
||||
{
|
||||
rs.FaviconAddress = iconAddressURI.ToString();
|
||||
rs.IconURL = iconAddressURI.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
33
MainForm.cs
33
MainForm.cs
@ -1,11 +1,13 @@
|
||||
using BookmarkManager;
|
||||
using bzit.bomg.Models;
|
||||
using FizzyLauncher.Models;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Newtonsoft.Json;
|
||||
using RyzStudio.Windows.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -23,7 +25,7 @@ namespace FizzyLauncher
|
||||
New
|
||||
}
|
||||
|
||||
|
||||
protected IconDatabase iconDatabase = null;
|
||||
protected OptionsForm optionsForm = null;
|
||||
protected FindForm findForm = null;
|
||||
|
||||
@ -39,13 +41,16 @@ namespace FizzyLauncher
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig");
|
||||
|
||||
if (iconDatabase == null) iconDatabase = new IconDatabase(Path.ChangeExtension(Application.ExecutablePath, "db"));
|
||||
iconDatabase.AddIcon(Guid.NewGuid().ToString(), UIResource.arrow_down);
|
||||
|
||||
this.AutoScaleMode = AutoScaleMode.None;
|
||||
this.StartPosition = FormStartPosition.WindowsDefaultLocation;
|
||||
this.ClientSize = new System.Drawing.Size(300, 580);
|
||||
//this.Visible = false;
|
||||
|
||||
jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig");
|
||||
|
||||
treeView1.RootContextMenu = rootContextMenu;
|
||||
treeView1.FolderContextMenu = folderContextMenu;
|
||||
treeView1.PageContextMenu = pageContextMenu;
|
||||
@ -71,6 +76,7 @@ namespace FizzyLauncher
|
||||
//ThreadControl.SetVisible(this, false);
|
||||
|
||||
await LoadAppSession(jsonfigFilename);
|
||||
//await InitialiseIconDB(iconDBFilename);
|
||||
|
||||
InvalidateAppSession();
|
||||
|
||||
@ -107,6 +113,7 @@ namespace FizzyLauncher
|
||||
sessionPassword = null;
|
||||
|
||||
treeView1.Clear();
|
||||
iconDatabase?.Close();
|
||||
|
||||
ApplicationMode = AppMode.Clear;
|
||||
|
||||
@ -680,10 +687,16 @@ namespace FizzyLauncher
|
||||
case Keys.F2:
|
||||
if (nodeType == BookmarkTreeView.NodeType.Page)
|
||||
{
|
||||
BookmarkForm bookmarkForm = new BookmarkForm(treeView1.GetNodeModel());
|
||||
BookmarkForm bookmarkForm = new BookmarkForm(treeView1.GetNodeModel(), null);
|
||||
if (bookmarkForm.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
treeView1.UpdateItem(treeView1.SelectedNode, bookmarkForm.Model, bookmarkForm.Favicon);
|
||||
string iconID = Crypto.GetSHA256Hash(bookmarkForm.Model.Item?.SiteName);
|
||||
if (!string.IsNullOrWhiteSpace(iconID))
|
||||
{
|
||||
iconDatabase.AddIcon(iconID, bookmarkForm.Model.Icon);
|
||||
}
|
||||
|
||||
treeView1.UpdateItem(treeView1.SelectedNode, bookmarkForm.Model.Item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -708,10 +721,16 @@ namespace FizzyLauncher
|
||||
node.EnsureVisible();
|
||||
treeView1.SelectedNode = node;
|
||||
|
||||
BookmarkForm bookmarkForm = new BookmarkForm(treeView1.GetNodeModel());
|
||||
BookmarkForm bookmarkForm = new BookmarkForm(treeView1.GetNodeModel(), null);
|
||||
if (bookmarkForm.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
treeView1.UpdateItem(treeView1.SelectedNode, bookmarkForm.Model, bookmarkForm.Favicon);
|
||||
string iconID = Crypto.GetSHA256Hash(bookmarkForm.Model.Item?.SiteName);
|
||||
if (!string.IsNullOrWhiteSpace(iconID))
|
||||
{
|
||||
iconDatabase.AddIcon(iconID, bookmarkForm.Model.Icon);
|
||||
}
|
||||
|
||||
treeView1.UpdateItem(treeView1.SelectedNode, bookmarkForm.Model.Item);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -11,23 +11,10 @@ namespace bzit.bomg.Models
|
||||
|
||||
public string SiteDescription { get; set; }
|
||||
|
||||
public string FaviconAddress { get; set; }
|
||||
|
||||
public string TreeviewPath { get; set; }
|
||||
|
||||
public string Notes { get; set; }
|
||||
|
||||
//public BookmarkItemModel ToModel()
|
||||
//{
|
||||
// return new BookmarkItemModel()
|
||||
// {
|
||||
// SiteName = this.SiteName,
|
||||
// SiteAddress = this.SiteAddress,
|
||||
// SiteDescription = this.SiteDescription,
|
||||
// FaviconAddress = this.FaviconAddress,
|
||||
// TreeviewPath = this.TreeviewPath
|
||||
// };
|
||||
//}
|
||||
|
||||
public new string ToString()
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using bzit.bomg;
|
||||
using BookmarkManager;
|
||||
using bzit.bomg;
|
||||
using bzit.bomg.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -519,6 +520,9 @@ namespace RyzStudio.Windows.Forms
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public IconDatabase IconDatabase { get; set; } = null;
|
||||
|
||||
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public ContextMenuStrip RootContextMenu { get; set; } = null;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user