mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-22 05:34:04 +02:00
fixed favicon support
This commit is contained in:
parent
ba0a408349
commit
a11bc18143
6 changed files with 336 additions and 43 deletions
41
app.vue
41
app.vue
|
@ -32,7 +32,7 @@
|
||||||
:class="['result clothoid-corner', { 'selected': isSelected(groupIndex, index) }]"
|
:class="['result clothoid-corner', { 'selected': isSelected(groupIndex, index) }]"
|
||||||
@click="selectItem(groupIndex, index)"
|
@click="selectItem(groupIndex, index)"
|
||||||
:ref="el => { if (isSelected(groupIndex, index)) selectedElement = el }">
|
:ref="el => { if (isSelected(groupIndex, index)) selectedElement = el }">
|
||||||
<img v-if="isUrl(item.content)" :src="getFavicon(item.content)" alt="Favicon" class="favicon">
|
<img v-if="isUrl(item.content)" :src="getFaviconFromDb(item.favicon)" alt="Favicon" class="favicon">
|
||||||
<FileIcon v-else />
|
<FileIcon v-else />
|
||||||
<img v-if="item.type === 'image'" :src="item.content" alt="Image" class="preview-image">
|
<img v-if="item.type === 'image'" :src="item.content" alt="Image" class="preview-image">
|
||||||
<span v-else>{{ truncateContent(item.content) }}</span>
|
<span v-else>{{ truncateContent(item.content) }}</span>
|
||||||
|
@ -178,8 +178,12 @@ const truncateContent = (content) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const isUrl = (str) => {
|
const isUrl = (str) => {
|
||||||
const urlPattern = /^(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
try {
|
||||||
return urlPattern.test(str);
|
new URL(str);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isYoutubeWatchUrl = (url) => {
|
const isYoutubeWatchUrl = (url) => {
|
||||||
|
@ -191,19 +195,32 @@ const getYoutubeThumbnail = (url) => {
|
||||||
return `https://img.youtube.com/vi/${videoId}/0.jpg`;
|
return `https://img.youtube.com/vi/${videoId}/0.jpg`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFavicon = (url) => {
|
const getFaviconFromDb = (favicon) => {
|
||||||
const domain = url.replace(/^(https?:\/\/)?(www\.)?/, '').split('/')[0];
|
return `data:image/png;base64,${favicon}`;
|
||||||
return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshHistory = async () => {
|
const refreshHistory = async () => {
|
||||||
const rawHistory = await db.value.select('SELECT * FROM history ORDER BY timestamp DESC');
|
history.value = [];
|
||||||
history.value = rawHistory.map(item => {
|
await loadMoreHistory();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadMoreHistory = async () => {
|
||||||
|
const lastTimestamp = history.value.length > 0 ? history.value[history.value.length - 1].timestamp : '9999-12-31T23:59:59Z';
|
||||||
|
const batchSize = 100;
|
||||||
|
|
||||||
|
const rawHistory = await db.value.select(
|
||||||
|
'SELECT * FROM history WHERE timestamp < ? ORDER BY timestamp DESC LIMIT ?',
|
||||||
|
[lastTimestamp, batchSize]
|
||||||
|
);
|
||||||
|
|
||||||
|
const newItems = rawHistory.map(item => {
|
||||||
if (item.type === 'image' && !item.content.startsWith('data:image')) {
|
if (item.type === 'image' && !item.content.startsWith('data:image')) {
|
||||||
return { ...item, content: `data:image/png;base64,${item.content}` };
|
return { ...item, content: `data:image/png;base64,${item.content}` };
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
history.value = [...history.value, ...newItems];
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
@ -234,6 +251,13 @@ onMounted(async () => {
|
||||||
await listen('tauri://blur', hideApp);
|
await listen('tauri://blur', hideApp);
|
||||||
await listen('tauri://focus', focusSearchInput);
|
await listen('tauri://focus', focusSearchInput);
|
||||||
focusSearchInput();
|
focusSearchInput();
|
||||||
|
|
||||||
|
const resultsElement = resultsContainer.value.$el;
|
||||||
|
resultsElement.addEventListener('scroll', () => {
|
||||||
|
if (resultsElement.scrollTop + resultsElement.clientHeight >= resultsElement.scrollHeight - 100) {
|
||||||
|
loadMoreHistory();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const hideApp = async () => {
|
const hideApp = async () => {
|
||||||
|
@ -242,6 +266,7 @@ const hideApp = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const showApp = async () => {
|
const showApp = async () => {
|
||||||
|
history.value = [];
|
||||||
await refreshHistory();
|
await refreshHistory();
|
||||||
await app.show();
|
await app.show();
|
||||||
await window.getCurrent().show();
|
await window.getCurrent().show();
|
||||||
|
|
217
src-tauri/Cargo.lock
generated
217
src-tauri/Cargo.lock
generated
|
@ -160,6 +160,12 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-waker"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "auto-launch"
|
name = "auto-launch"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -987,6 +993,15 @@ version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -1594,6 +1609,25 @@ dependencies = [
|
||||||
"syn 2.0.68",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"http",
|
||||||
|
"indexmap 2.2.6",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
|
@ -1746,6 +1780,7 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"h2",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
@ -1756,6 +1791,39 @@ dependencies = [
|
||||||
"want",
|
"want",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.27.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
@ -2537,6 +2605,15 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc"
|
name = "objc"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -3146,12 +3223,15 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arboard",
|
"arboard",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"clipboard-win",
|
|
||||||
"image 0.25.1",
|
"image 0.25.1",
|
||||||
|
"log",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rdev",
|
"rdev",
|
||||||
|
"regex",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"simplelog",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
|
@ -3162,6 +3242,7 @@ dependencies = [
|
||||||
"tauri-plugin-sql",
|
"tauri-plugin-sql",
|
||||||
"tauri-plugin-window-state",
|
"tauri-plugin-window-state",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3448,25 +3529,34 @@ checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"h2",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
"hyper-rustls",
|
||||||
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
|
"native-tls",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"url",
|
"url",
|
||||||
|
@ -3486,6 +3576,21 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom 0.2.15",
|
||||||
|
"libc",
|
||||||
|
"spin",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.9.6"
|
version = "0.9.6"
|
||||||
|
@ -3534,6 +3639,46 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.23.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.102.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
@ -3866,6 +4011,17 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simplelog"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"termcolor",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -4286,6 +4442,27 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation 0.9.4",
|
||||||
|
"system-configuration-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys 0.8.6",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "6.2.2"
|
version = "6.2.2"
|
||||||
|
@ -4693,6 +4870,15 @@ dependencies = [
|
||||||
"utf-8",
|
"utf-8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thin-slice"
|
name = "thin-slice"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -4748,7 +4934,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"itoa 1.0.11",
|
"itoa 1.0.11",
|
||||||
|
"libc",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
|
"num_threads",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
"serde",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
@ -4816,6 +5004,27 @@ dependencies = [
|
||||||
"syn 2.0.68",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.26.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-stream"
|
name = "tokio-stream"
|
||||||
version = "0.1.15"
|
version = "0.1.15"
|
||||||
|
@ -5106,6 +5315,12 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.2"
|
version = "2.5.2"
|
||||||
|
|
|
@ -26,4 +26,8 @@ rand = "0.8"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
arboard = "3.4.0"
|
arboard = "3.4.0"
|
||||||
image = "0.25.1"
|
image = "0.25.1"
|
||||||
clipboard-win = "5.3.1"
|
reqwest = { version = "0.12.5", features = ["blocking"] }
|
||||||
|
url = "2.5.2"
|
||||||
|
log = "0.4"
|
||||||
|
simplelog = "0.12.2"
|
||||||
|
regex = "1"
|
|
@ -1,6 +1,5 @@
|
||||||
use base64::engine::general_purpose::STANDARD;
|
use base64::engine::general_purpose::STANDARD;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use clipboard_win::{formats, get_clipboard, is_format_avail};
|
|
||||||
use rand::distributions::Alphanumeric;
|
use rand::distributions::Alphanumeric;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use rdev::{listen, simulate, EventType, Key};
|
use rdev::{listen, simulate, EventType, Key};
|
||||||
|
@ -10,6 +9,10 @@ use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
use url::Url;
|
||||||
|
use reqwest::Client;
|
||||||
|
use arboard::Clipboard;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn simulate_paste() {
|
pub fn simulate_paste() {
|
||||||
|
@ -30,6 +33,7 @@ pub fn simulate_paste() {
|
||||||
|
|
||||||
pub fn setup(app_handle: tauri::AppHandle) {
|
pub fn setup(app_handle: tauri::AppHandle) {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let mut is_processing = false;
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
listen(move |event| match event.event_type {
|
listen(move |event| match event.event_type {
|
||||||
|
@ -37,33 +41,30 @@ pub fn setup(app_handle: tauri::AppHandle) {
|
||||||
let _ = tx.send(true);
|
let _ = tx.send(true);
|
||||||
}
|
}
|
||||||
EventType::KeyRelease(Key::KeyC) => {
|
EventType::KeyRelease(Key::KeyC) => {
|
||||||
if rx.try_recv().is_ok() {
|
if rx.try_recv().is_ok() && !is_processing {
|
||||||
|
is_processing = true;
|
||||||
let pool = app_handle.state::<SqlitePool>();
|
let pool = app_handle.state::<SqlitePool>();
|
||||||
let rt = app_handle.state::<Runtime>();
|
let rt = app_handle.state::<Runtime>();
|
||||||
|
|
||||||
if let Ok(content) = get_clipboard(formats::Unicode) {
|
let mut clipboard = Clipboard::new().unwrap();
|
||||||
|
|
||||||
|
if let Ok(content) = clipboard.get_text() {
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
insert_content_if_not_exists(&pool, "text", content).await;
|
insert_content_if_not_exists(&pool, "text", content).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_format_avail(formats::Bitmap.into()) {
|
if let Ok(image) = clipboard.get_image() {
|
||||||
match get_clipboard(formats::Bitmap) {
|
|
||||||
Ok(image) => {
|
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
let base64_image = STANDARD.encode(&image);
|
let base64_image = STANDARD.encode(&image.bytes);
|
||||||
insert_content_if_not_exists(&pool, "image", base64_image)
|
insert_content_if_not_exists(&pool, "image", base64_image).await;
|
||||||
.await;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
is_processing = false;
|
||||||
println!("Error reading image from clipboard: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("No image format available in clipboard");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EventType::KeyRelease(Key::ControlLeft | Key::ControlRight) => {
|
||||||
|
is_processing = false;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
})
|
})
|
||||||
|
@ -72,27 +73,74 @@ pub fn setup(app_handle: tauri::AppHandle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn insert_content_if_not_exists(pool: &SqlitePool, content_type: &str, content: String) {
|
async fn insert_content_if_not_exists(pool: &SqlitePool, content_type: &str, content: String) {
|
||||||
let exists: bool = sqlx::query_scalar(
|
let last_content: Option<String> = sqlx::query_scalar(
|
||||||
"SELECT EXISTS(SELECT 1 FROM history WHERE content_type = ? AND content = ?)",
|
"SELECT content FROM history WHERE content_type = ? ORDER BY timestamp DESC LIMIT 1",
|
||||||
)
|
)
|
||||||
.bind(content_type)
|
.bind(content_type)
|
||||||
.bind(&content)
|
|
||||||
.fetch_one(pool)
|
.fetch_one(pool)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(false);
|
.unwrap_or(None);
|
||||||
|
|
||||||
if !exists {
|
if last_content.as_deref() != Some(&content) {
|
||||||
let id: String = thread_rng()
|
let id: String = thread_rng()
|
||||||
.sample_iter(&Alphanumeric)
|
.sample_iter(&Alphanumeric)
|
||||||
.take(16)
|
.take(16)
|
||||||
.map(char::from)
|
.map(char::from)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let _ = sqlx::query("INSERT INTO history (id, content_type, content) VALUES (?, ?, ?)")
|
let url_regex = Regex::new(r"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)").unwrap();
|
||||||
|
let favicon_base64 = if content_type == "text" {
|
||||||
|
if let Some(url_match) = url_regex.find(&content) {
|
||||||
|
let url_str = url_match.as_str();
|
||||||
|
match Url::parse(url_str) {
|
||||||
|
Ok(url) => {
|
||||||
|
match fetch_favicon_as_base64(url).await {
|
||||||
|
Ok(Some(favicon)) => {
|
||||||
|
println!("Favicon fetched successfully.");
|
||||||
|
Some(favicon)
|
||||||
|
},
|
||||||
|
Ok(None) => {
|
||||||
|
println!("No favicon found.");
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to fetch favicon: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to parse URL: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = sqlx::query("INSERT INTO history (id, content_type, content, favicon) VALUES (?, ?, ?, ?)")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.bind(content_type)
|
.bind(content_type)
|
||||||
.bind(content)
|
.bind(content)
|
||||||
|
.bind(favicon_base64)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_favicon_as_base64(url: Url) -> Result<Option<String>, reqwest::Error> {
|
||||||
|
println!("Checking for favicon at URL: {}", url.origin().ascii_serialization());
|
||||||
|
let client = Client::new();
|
||||||
|
let favicon_url = format!("https://icon.horse/icon/{}", url.host_str().unwrap());
|
||||||
|
let response = client.get(&favicon_url).send().await?;
|
||||||
|
|
||||||
|
if response.status().is_success() {
|
||||||
|
let bytes = response.bytes().await?;
|
||||||
|
Ok(Some(STANDARD.encode(&bytes)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
content_type TEXT NOT NULL,
|
content_type TEXT NOT NULL,
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL,
|
||||||
|
favicon TEXT,
|
||||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)"
|
)"
|
||||||
)
|
)
|
||||||
|
@ -45,7 +46,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.take(16)
|
.take(16)
|
||||||
.map(char::from)
|
.map(char::from)
|
||||||
.collect();
|
.collect();
|
||||||
sqlx::query("INSERT INTO history (id, content_type, content) VALUES (?, ?, ?)")
|
sqlx::query("INSERT INTO history (id, content_type, content, timestamp) VALUES (?, ?, ?, CURRENT_TIMESTAMP)")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.bind("text")
|
.bind("text")
|
||||||
.bind("Welcome to your clipboard history!")
|
.bind("Welcome to your clipboard history!")
|
||||||
|
|
|
@ -50,15 +50,15 @@ fn main() {
|
||||||
if let Some(window) = app.get_window("main") {
|
if let Some(window) = app.get_window("main") {
|
||||||
let _ = window.restore_state(StateFlags::POSITION);
|
let _ = window.restore_state(StateFlags::POSITION);
|
||||||
center_window_on_current_monitor(&window);
|
center_window_on_current_monitor(&window);
|
||||||
window.show().unwrap();
|
window.hide().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(dev)]
|
// #[cfg(dev)]
|
||||||
{
|
// {
|
||||||
let window = app.get_webview_window("main").unwrap();
|
// let window = app.get_webview_window("main").unwrap();
|
||||||
window.open_devtools();
|
// window.open_devtools();
|
||||||
window.close_devtools();
|
// window.close_devtools();
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue