This repository has been archived on 2022-09-30. You can view files and clone it, but cannot push or open issues or pull requests.
bookmark-manager/BookmarkItem.cs
2017-07-30 12:59:34 +01:00

386 lines
12 KiB
C#

using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Net;
using System.Windows.Forms;
namespace bzit.bomg
{
public class BookmarkItem
{
public delegate void RetrieveCompleted(BookmarkItem sender, bool hasError, string message);
protected const char pathSeparator = '|';
protected TreeNode treeNode = null;
protected BackgroundWorker mainThread = null;
protected bool hasRetrieveError = false;
protected string retrieveErrorMessage = null;
public BookmarkItem()
{
this.Clear();
}
public new string ToString()
{
string rv = "";
rv += "Name=" + this.Fullpath + Environment.NewLine;
rv += "Address=" + this.Address + Environment.NewLine;
rv += "Description=" + this.Description + Environment.NewLine;
rv += "Created=" + this.Created?.Trim();
return rv;
}
#region public properties
public TreeNode TreeViewNode
{
get
{
return this.treeNode;
}
set
{
this.treeNode = value;
}
}
public Bitmap Icon
{
get
{
if (this.IconData == null)
{
return null;
}
try
{
Image img = Image.FromStream(new MemoryStream(this.IconData));
return new Bitmap(img, 16, 16);
}
catch
{
return null;
}
}
}
[DefaultValue(null)]
public byte[] IconData { get; set; }
public string Created { get; set; }
public string TempName { get; set; }
public string Fullpath { get; set; }
public string IconAddress { get; set; }
public string Address { get; set; }
public string Description { get; set; }
#endregion
#region public methods
public void Clear()
{
this.Fullpath = string.Empty;
this.Address = string.Empty;
this.Description = string.Empty;
this.Created = string.Empty;
if (this.mainThread == null)
{
this.mainThread = new BackgroundWorker();
this.mainThread.WorkerReportsProgress = this.mainThread.WorkerSupportsCancellation = true;
this.mainThread.DoWork += retrieveWorker_DoWork;
this.mainThread.RunWorkerCompleted += retrieveWorker_RunWorkerCompleted;
}
}
public string GetName()
{
if (this.Fullpath.Contains(pathSeparator.ToString()))
{
return PathDecode(this.Fullpath.Substring(this.Fullpath.LastIndexOf(pathSeparator) + 1)).Trim();
}
return PathDecode(this.Fullpath).Trim();
}
public void ChangeName(string newName)
{
string prefix = (this.Fullpath.Contains(pathSeparator.ToString()) ? this.Fullpath.Substring(0, this.Fullpath.IndexOf(pathSeparator)).Trim() : string.Empty);
this.Fullpath = string.Concat(prefix, pathSeparator, PathEncode(newName.Trim()));
}
public void GetFaviconAddress()
{
hasRetrieveError = false;
retrieveErrorMessage = string.Empty;
this.IconData = null;
WebClient webClient = new WebClient();
webClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
string sourceCode = string.Empty;
try
{
sourceCode = webClient.DownloadString(this.Address);
}
catch (Exception exc)
{
hasRetrieveError = true;
retrieveErrorMessage = exc.Message;
return;
}
HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
document.LoadHtml(sourceCode);
// parse icon
HtmlAgilityPack.HtmlNodeCollection hnc = document.DocumentNode.SelectNodes("//link");
if (hnc != null)
{
foreach (HtmlAgilityPack.HtmlNode node in hnc)
{
if (node.Attributes["rel"] == null)
{
continue;
}
string nodeAttr = node.Attributes["rel"].Value.Trim();
if (nodeAttr.ToLower().Contains("icon"))
{
if (!string.IsNullOrEmpty(this.IconAddress))
{
continue;
}
if (node.Attributes["href"] != null)
{
Uri iconPath;
bool rv = Uri.TryCreate(new Uri(this.Address), WebUtility.HtmlDecode(node.Attributes["href"].Value).Trim(), out iconPath);
if (rv)
{
this.IconAddress = iconPath.ToString();
}
break;
}
}
}
}
// default favicon
if (string.IsNullOrEmpty(this.IconAddress))
{
Uri iconPath;
if (Uri.TryCreate(new Uri(this.Address), "/favicon.ico", out iconPath))
{
this.IconAddress = iconPath.ToString();
}
}
// load icon image
if (!string.IsNullOrEmpty(this.IconAddress))
{
try
{
this.IconData = webClient.DownloadData(this.IconAddress);
if (!RyzStudio.IO.FileType.IsImage(this.IconData))
{
this.IconData = null;
}
}
catch
{
// do nothing
}
}
}
public void RetrieveAsync()
{
if (this.mainThread.IsBusy)
{
return;
}
this.mainThread.RunWorkerAsync();
}
public void RetrieveAsync(string address)
{
if (this.mainThread.IsBusy)
{
return;
}
this.Address = address;
this.mainThread.RunWorkerAsync();
}
#endregion
#region events & delegate
public RetrieveCompleted OnRetrieveCompleted = null;
#endregion
protected void retrieveWorker_DoWork(object sender, DoWorkEventArgs e)
{
hasRetrieveError = false;
retrieveErrorMessage = string.Empty;
this.IconData = null;
this.Fullpath = string.Empty;
this.Description = string.Empty;
this.IconAddress = string.Empty;
WebClient webClient = new WebClient();
webClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
string sourceCode = string.Empty;
try
{
sourceCode = webClient.DownloadString(this.Address);
}
catch (Exception exc)
{
hasRetrieveError = true;
retrieveErrorMessage = exc.Message;
return;
}
HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
document.LoadHtml(sourceCode);
// parse title
HtmlAgilityPack.HtmlNodeCollection hnc = document.DocumentNode.SelectNodes("//title");
if (hnc != null)
{
if (hnc.Count > 0)
{
this.TempName = WebUtility.HtmlDecode(hnc[0].InnerHtml).Trim();
}
}
// parse description
hnc = document.DocumentNode.SelectNodes("//meta");
if (hnc != null)
{
foreach (HtmlAgilityPack.HtmlNode node in hnc)
{
if (node.Attributes["name"] == null)
{
continue;
}
string nodeAttr = node.Attributes["name"].Value.Trim();
if (nodeAttr.Equals("description", StringComparison.CurrentCultureIgnoreCase))
{
if (!string.IsNullOrEmpty(this.Description))
{
continue;
}
if (node.Attributes["content"] != null)
{
this.Description = WebUtility.HtmlDecode(node.Attributes["content"].Value).Trim();
break;
}
}
}
}
// parse icon
hnc = document.DocumentNode.SelectNodes("//link");
if (hnc != null)
{
foreach (HtmlAgilityPack.HtmlNode node in hnc)
{
if (node.Attributes["rel"] == null)
{
continue;
}
string nodeAttr = node.Attributes["rel"].Value.Trim();
if (nodeAttr.ToLower().Contains("icon"))
{
if (!string.IsNullOrEmpty(this.IconAddress))
{
continue;
}
if (node.Attributes["href"] != null)
{
Uri iconPath;
bool rv = Uri.TryCreate(new Uri(this.Address), WebUtility.HtmlDecode(node.Attributes["href"].Value).Trim(), out iconPath);
if (rv)
{
this.IconAddress = iconPath.ToString();
}
break;
}
}
}
}
// default favicon
if (string.IsNullOrEmpty(this.IconAddress))
{
Uri iconPath;
if (Uri.TryCreate(new Uri(this.Address), "/favicon.ico", out iconPath))
{
this.IconAddress = iconPath.ToString();
}
}
// load icon image
if (!string.IsNullOrEmpty(this.IconAddress))
{
try
{
this.IconData = webClient.DownloadData(this.IconAddress);
if (!RyzStudio.IO.FileType.IsImage(this.IconData))
{
this.IconData = null;
}
}
catch
{
// do nothing
}
}
}
protected void retrieveWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.OnRetrieveCompleted?.Invoke(this, hasRetrieveError, retrieveErrorMessage);
}
// protected string CustomDecode(string text) { return WebUtility.HtmlDecode(text); }
////protected string PathEncode(string text) { return RyzStudio.String.EncodeTo64(text); }
////protected string PathDecode(string text) { return RyzStudio.String.DecodeFrom64(text); }
protected string PathEncode(string text) { return System.Web.HttpUtility.UrlEncodeUnicode(text); }
protected string PathDecode(string text) { return System.Web.HttpUtility.UrlDecode(text); }
}
}