=> {
+ if (!canShare()) {
+ useNotification().error('Web Share API is not supported in this browser.');
+ return;
+ }
+
+ try {
+ const title = download.title || download.filename || 'Download';
+ await navigator.share({
+ title: title,
+ text: download.description || title,
+ url: makeDownload(useYtpConfig(), download),
+ });
+ } catch (err: any) {
+ if (err?.name === 'AbortError') {
+ return;
+ }
+
+ console.error('Share failed:', err);
+
+ await useDialog().alertDialog({
+ title: 'Share Failed',
+ message: `Share failed: ${err?.message || 'unknown error'}`,
+ });
+ }
+ };
+
+ return { canShare, shareUrl };
+};
diff --git a/ui/app/pages/history.vue b/ui/app/pages/history.vue
index 37d05ef1..112e5327 100644
--- a/ui/app/pages/history.vue
+++ b/ui/app/pages/history.vue
@@ -28,6 +28,16 @@
+
+ Add
+
+
+ shareUrl(item)"
+ />
+
+ shareUrl(item)"
+ >
+ Share
+
+
>(
'pending-download-form-item',
() => ({}),
@@ -885,6 +917,8 @@ watch(video_item, (value) => {
document.querySelector('body')?.setAttribute('style', `opacity: ${value ? 1 : bg_opacity.value}`);
});
+const canShareUrl = computed(() => canShare());
+
watch(embed_url, (value) => {
if (!bg_enable.value) {
return;
@@ -933,6 +967,12 @@ const changeDisplay = (): void => {
display_style.value = display_style.value === 'grid' ? 'list' : 'grid';
};
+const addNewDownload = async (): Promise => {
+ config.showForm = true;
+ await nextTick();
+ await navigateTo('/');
+};
+
const toNewDownload = async (item: item_request | Partial): Promise => {
if (!item) {
return;
diff --git a/ui/app/utils/index.ts b/ui/app/utils/index.ts
index 49655989..da333abf 100644
--- a/ui/app/utils/index.ts
+++ b/ui/app/utils/index.ts
@@ -476,8 +476,7 @@ const makeDownload = (
}
if (item.folder) {
- item.folder = item.folder.replace(/#/g, '%23');
- baseDir += item.folder + '/';
+ baseDir += item.folder.replace(/#/g, '%23') + '/';
}
if (!item.filename) {