feat: add share button
This commit is contained in:
parent
d6318fca0f
commit
196d2d4e32
5 changed files with 95 additions and 13 deletions
25
README.md
25
README.md
|
|
@ -50,17 +50,22 @@ Please read the [FAQ](FAQ.md) for more information.
|
|||
## Run using docker command
|
||||
|
||||
```bash
|
||||
mkdir -p ./{config,downloads/files,downloads/tmp} && docker run -itd --rm --user "${UID}:${UID}" --name ytptube \
|
||||
mkdir -p ./{config,downloads/{files,tmp}} && docker run -itd --rm --user "${UID}:${UID}" --name ytptube \
|
||||
-e YTP_TEMP_PATH=/downloads/tmp -e YTP_DOWNLOAD_PATH=/downloads/files \
|
||||
-p 8081:8081 -v ./config:/config:rw -v ./downloads:/downloads:rw \
|
||||
ghcr.io/arabcoders/ytptube:latest
|
||||
```
|
||||
|
||||
Then you can access the WebUI at `http://localhost:8081`.
|
||||
## Run using podman
|
||||
|
||||
> [!NOTE]
|
||||
> If you are using `podman` instead of `docker`, you can use the same command, but you need to change the user to `0:0`
|
||||
> it will appears to be running as root, but it will run as the user who started the container.
|
||||
```bash
|
||||
mkdir -p ./{config,downloads/{files,tmp}} && podman run -itd --rm --userns=keep-id --name ytptube \
|
||||
-e YTP_TEMP_PATH=/downloads/tmp -e YTP_DOWNLOAD_PATH=/downloads/files \
|
||||
-p 8081:8081 -v ./config:/config:rw -v ./downloads:/downloads:rw \
|
||||
arabcoders/ytptube:latest
|
||||
```
|
||||
|
||||
Then you can access the WebUI at `http://localhost:8081`.
|
||||
|
||||
## Using compose file
|
||||
|
||||
|
|
@ -70,6 +75,8 @@ The following is an example of a `compose.yaml` file that can be used to run YTP
|
|||
services:
|
||||
ytptube:
|
||||
user: "${UID:-1000}:${UID:-1000}" # change this to your user id and group id.
|
||||
# comment out the above line and uncomment the below line if you are using podman-compose.
|
||||
#userns_mode: keep-id
|
||||
image: ghcr.io/arabcoders/ytptube:latest
|
||||
container_name: ytptube
|
||||
restart: unless-stopped
|
||||
|
|
@ -84,18 +91,14 @@ services:
|
|||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Make sure to change the `user` line to match your user id and group id.
|
||||
> Make sure to change the `user` line to match your user id and group id in docker setups, or use `userns_mode: keep-id` in podman setups.
|
||||
|
||||
```bash
|
||||
mkdir -p ./{config,downloads/files,downloads/tmp} && docker compose -f compose.yaml up -d
|
||||
mkdir -p ./{config,downloads/{files,tmp}} && docker compose -f compose.yaml up -d
|
||||
```
|
||||
|
||||
Then you can access the WebUI at `http://localhost:8081`.
|
||||
|
||||
> [!NOTE]
|
||||
> you can use podman-compose instead of docker-compose, as it supports the same syntax. However, you should change the
|
||||
> user to `0:0` it will appears to be running as root, but it will run as the user who started the container.
|
||||
|
||||
## Unraid
|
||||
|
||||
For `Unraid` users You can install the `Community Applications` plugin, and search for **ytptube** it comes
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
base: 'min-h-[7.25rem] bg-elevated/60 ring-default focus-visible:ring-primary',
|
||||
}"
|
||||
@keydown="handleKeyDown"
|
||||
autofocus
|
||||
/>
|
||||
<UInput
|
||||
v-else
|
||||
|
|
@ -55,6 +56,7 @@
|
|||
}"
|
||||
@keydown="handleKeyDown"
|
||||
@paste="handlePaste"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
38
ui/app/composables/useWebShare.ts
Normal file
38
ui/app/composables/useWebShare.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { useDialog } from './useDialog';
|
||||
import { useYtpConfig } from './useYtpConfig';
|
||||
import { makeDownload } from '~/utils';
|
||||
import type { StoreItem } from '~/types/store';
|
||||
|
||||
export const useWebShare = () => {
|
||||
const canShare = (): boolean =>
|
||||
typeof navigator !== 'undefined' && typeof navigator.share === 'function';
|
||||
|
||||
const shareUrl = async (download: StoreItem): Promise<void> => {
|
||||
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 };
|
||||
};
|
||||
|
|
@ -28,6 +28,16 @@
|
|||
</div>
|
||||
|
||||
<div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
icon="i-lucide-plus"
|
||||
@click="addNewDownload"
|
||||
>
|
||||
<span>Add</span>
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
color="neutral"
|
||||
:variant="showFilter ? 'soft' : 'outline'"
|
||||
|
|
@ -326,6 +336,15 @@
|
|||
Retry
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-if="item.filename && canShareUrl"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
size="xs"
|
||||
icon="i-lucide-share"
|
||||
@click="() => shareUrl(item)"
|
||||
/>
|
||||
|
||||
<UButton
|
||||
v-if="item.filename"
|
||||
color="neutral"
|
||||
|
|
@ -620,6 +639,17 @@
|
|||
Retry
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-if="item.filename && canShareUrl"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
icon="i-lucide-share"
|
||||
class="w-full justify-center"
|
||||
@click="() => shareUrl(item)"
|
||||
>
|
||||
Share
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-if="item.filename"
|
||||
color="neutral"
|
||||
|
|
@ -774,6 +804,7 @@ import { useAppSocket } from '~/composables/useAppSocket';
|
|||
import { useExpandableMeta } from '~/composables/useExpandableMeta';
|
||||
import { useHistoryState } from '~/composables/useHistoryState';
|
||||
import { useMediaQuery } from '~/composables/useMediaQuery';
|
||||
import { useWebShare } from '~/composables/useWebShare';
|
||||
import type { item_request } from '~/types/item';
|
||||
import type { StoreItem } from '~/types/store';
|
||||
import {
|
||||
|
|
@ -798,6 +829,7 @@ const toast = useNotification();
|
|||
const box = useConfirm();
|
||||
const { confirmDialog, promptDialog } = useDialog();
|
||||
const { toggleExpand, expandClass } = useExpandableMeta();
|
||||
const { canShare, shareUrl } = useWebShare();
|
||||
const pendingDownloadFormItem = useState<item_request | Record<string, never>>(
|
||||
'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<void> => {
|
||||
config.showForm = true;
|
||||
await nextTick();
|
||||
await navigateTo('/');
|
||||
};
|
||||
|
||||
const toNewDownload = async (item: item_request | Partial<StoreItem>): Promise<void> => {
|
||||
if (!item) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue