using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Web;
// The 'text' parameter will contain the text from the:
// - Current Clipboard when run by HotKey
// - History Item when run from the History Menu
// The returned string will be:
// - Placed directly on the Clipboard when run as a Macro
// - Ignored by ClipboardFusion if it is 'null'
// - Passed along to the next action in a Trigger (null changed to an empty string)
public static class ClipboardFusionHelper
{
public static string ProcessText(string text)
{
// Check to see if the text is a valid url.
// If it isn't, return null
if(!Uri.TryCreate(text, UriKind.Absolute, out Uri uri))
return null;
// Get the title from the url
string title = GetPageTitleFromUrl(uri).Result;
// Create the link out of the text and the title. this needs to be valid html
// or other programs to accept it, so it's also surrounded by body and html tags
string link = $"<html><body><a href=\"{text}\">{title}</a></body></html>";
// Create a data object for the clipboard
DataObject clipboard = new DataObject();
// Set the html format
clipboard.SetData(DataFormats.Html, GenerateHtmlClipboardFormat(link));
// Set the raw link as the text format
clipboard.SetData(DataFormats.Text, text);
// Set the clipboard with the data object and make the data available even when ClipboardFusion exits
Clipboard.SetDataObject(clipboard, true);
// Since we already set the clipboard ourselves tell CF that we handled it
return null;
}
private static string GenerateHtmlClipboardFormat(string html)
{
// https://learn.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format
// Create the header for the html format
string header = "Version:1.0\r\n" +
"StartHTML:-1\r\n" +
"EndHTML:-1\r\n" +
"StartFragment:0000000000\r\n" +
"EndFragment:0000000000\r\n";
// Grab the offsets from the content
int startFragment = Encoding.UTF8.GetBytes(header).Length;
int endFragment = startFragment + Encoding.UTF8.GetBytes(html).Length;
// Finish building the header
header = header
.Replace("StartFragment:0000000000", $"StartFragment:{startFragment:D10}")
.Replace("EndFragment:0000000000", $"EndFragment:{endFragment:D10}");
// Return the html clipboard format
return header + html;
}
private static async Task<string> GetPageTitleFromUrl(Uri uri)
{
try
{
using (HttpClient client = new HttpClient())
{
// Get the html from the uri
var response = await client.GetAsync(uri);
// Get the web source
string body = await response.Content.ReadAsStringAsync();
// Grab the title and return it
return Regex.Match(body, @"(?<=<title>).*?(?=</title>)", RegexOptions.Multiline).ToString();
}
}
catch
{
// If we ran into an issue just return an empty string
return uri.ToString();
}
}
}