Added video hiding & video sharing

This commit is contained in:
WardPearce
2024-05-09 11:15:15 +12:00
parent e7a8bc41d1
commit 1019457a4b
5 changed files with 193 additions and 146 deletions
+33
View File
@@ -0,0 +1,33 @@
<script lang="ts">
import { Capacitor } from '@capacitor/core';
import { _ } from 'svelte-i18n';
import type { Notification, PlaylistPageVideo, Video, VideoBase } from './Api/model';
export let video: VideoBase | Video | Notification | PlaylistPageVideo;
</script>
{#if !Capacitor.isNativePlatform()}
<a
class="row"
href="#copy"
on:click={async () =>
await navigator.clipboard.writeText(`${location.origin}watch/${video.videoId}`)}
>
<div class="min">{$_('player.share.materialiousLink')}</div></a
>
{/if}
<a
href="#copy"
class="row"
on:click={async () =>
await navigator.clipboard.writeText(`https://redirect.invidious.io/watch?v=${video.videoId}`)}
>
<div class="min">{$_('player.share.invidiousRedirect')}</div></a
><a
class="row"
href="#copy"
on:click={async () =>
await navigator.clipboard.writeText(`https://www.youtube.com/watch?v=${video.videoId}`)}
>
<div class="min">{$_('player.share.youtubeLink')}</div></a
>
+141 -106
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { createEventDispatcher, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { get } from 'svelte/store';
import {
@@ -14,12 +14,16 @@
} from '../store';
import { getDeArrow, getThumbnail, getVideo, getVideoProgress } from './Api';
import type { Notification, PlaylistPageVideo, Video, VideoBase, VideoPlay } from './Api/model';
import ShareVideo from './ShareVideo.svelte';
import { cleanNumber, getBestThumbnail, proxyVideoUrl, videoLength } from './misc';
import type { PlayerEvents } from './player';
const dispatch = createEventDispatcher();
export let video: VideoBase | Video | Notification | PlaylistPageVideo;
export let playlistId: string = '';
let thumbnailHidden: boolean = false;
let showVideoPreview: boolean = false;
let videoPreview: VideoPlay | null = null;
let videoPreviewMuted: boolean = true;
@@ -56,6 +60,15 @@
}
onMount(async () => {
try {
thumbnailHidden = localStorage.getItem(`v_h_${video.videoId}`) === '1';
} catch {}
if (thumbnailHidden) {
dispatch('videoHidden');
return;
}
let imageSrc = getBestThumbnail(video.videoThumbnails);
if (get(deArrowEnabledStore)) {
@@ -180,119 +193,141 @@
showVideoPreview = true;
}
}
function hideVideo() {
try {
localStorage.setItem(`v_h_${video.videoId}`, '1');
dispatch('videoHidden');
thumbnailHidden = true;
} catch {}
}
</script>
<div
style="position: relative;"
on:mouseover={previewVideo}
on:mouseleave={() => (showVideoPreview = false)}
on:focus={() => {}}
role="region"
>
<a
class="wave thumbnail"
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
on:click={syncChangeVideo}
{#if !thumbnailHidden}
<div
style="position: relative;"
on:mouseover={previewVideo}
on:mouseleave={() => (showVideoPreview = false)}
on:focus={() => {}}
role="region"
>
{#if loading}
<progress class="circle"></progress>
{:else if loaded}
{#if showVideoPreview && videoPreview}
<div style="max-width: 100%; max-height: 200px;">
<video
style="max-width: 100%; max-height: 200px;"
autoplay
poster={img.src}
width="100%"
height="100%"
muted={videoPreviewMuted}
controls={false}
volume={videoPreviewVolume}
src={proxyVideos
? proxyVideoUrl(videoPreview.formatStreams[0].url)
: videoPreview.formatStreams[0].url}
>
</video>
</div>
{:else}
<img
class="responsive"
style="max-width: 100%;min-height: 160px;"
src={img.src}
alt="Thumbnail for video"
/>
{/if}
{:else}
<p>{$_('thumbnail.failedToLoadImage')}</p>
{/if}
{#if progress}
<progress
class="absolute right bottom"
style="z-index: 1;"
value={progress}
max={video.lengthSeconds}
></progress>
{/if}
{#if !('liveVideo' in video) || !video.liveVideo}
{#if video.lengthSeconds !== 0}
<div
class="absolute right bottom small-margin black white-text small-text thumbnail-corner"
>
&nbsp;{videoLength(video.lengthSeconds)}&nbsp;
</div>
{/if}
{:else}
<div class="absolute right bottom small-margin red white-text small-text thumbnail-corner">
{$_('thumbnail.live')}
</div>
{/if}
</a>
{#if showVideoPreview && videoPreview}
<button
class="no-padding"
style="position: absolute; bottom: 10px; left: 10px; width: 30px; height: 30px;"
on:click={() => {
videoPreviewMuted = !videoPreviewMuted;
}}
<a
class="wave thumbnail"
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
on:click={syncChangeVideo}
>
<i>
{#if videoPreviewMuted}
volume_off
{#if loading}
<progress class="circle"></progress>
{:else if loaded}
{#if showVideoPreview && videoPreview}
<div style="max-width: 100%; max-height: 200px;">
<video
style="max-width: 100%; max-height: 200px;"
autoplay
poster={img.src}
width="100%"
height="100%"
muted={videoPreviewMuted}
controls={false}
volume={videoPreviewVolume}
src={proxyVideos
? proxyVideoUrl(videoPreview.formatStreams[0].url)
: videoPreview.formatStreams[0].url}
>
</video>
</div>
{:else}
volume_up
<img
class="responsive"
style="max-width: 100%;min-height: 160px;"
src={img.src}
alt="Thumbnail for video"
/>
{/if}
</i>
</button>
{/if}
</div>
<div class="small-padding">
<nav class="no-margin">
<div class="max">
<a
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
style="display: flex; justify-content:flex-start; position: absolute; width: 100%;"
><div class="bold" style="white-space: nowrap; overflow: hidden;text-overflow: ellipsis;">
{video.title}
</div>
<div class="tooltip bottom small">{video.title}</div>
</a>
<div style="margin-top: 1.4em;">
<a href={`/channel/${video.authorId}`}>{video.author}</a
>{#if !('publishedText' in video) && 'viewCountText' in video}
&nbsp;{video.viewCountText}{/if}
</div>
{#if 'publishedText' in video}
<div>
{cleanNumber(video.viewCount)}{video.publishedText}
{:else}
<p>{$_('thumbnail.failedToLoadImage')}</p>
{/if}
{#if progress}
<progress
class="absolute right bottom"
style="z-index: 1;"
value={progress}
max={video.lengthSeconds}
></progress>
{/if}
{#if !('liveVideo' in video) || !video.liveVideo}
{#if video.lengthSeconds !== 0}
<div
class="absolute right bottom small-margin black white-text small-text thumbnail-corner"
>
&nbsp;{videoLength(video.lengthSeconds)}&nbsp;
</div>
{/if}
{:else}
<div class="absolute right bottom small-margin red white-text small-text thumbnail-corner">
{$_('thumbnail.live')}
</div>
{/if}
</div>
</nav>
</div>
</a>
{#if showVideoPreview && videoPreview}
<button
class="no-padding"
style="position: absolute; bottom: 10px; left: 10px; width: 30px; height: 30px;"
on:click={() => {
videoPreviewMuted = !videoPreviewMuted;
}}
>
<i>
{#if videoPreviewMuted}
volume_off
{:else}
volume_up
{/if}
</i>
</button>
{/if}
</div>
<div class="small-padding">
<nav class="no-margin">
<div class="max">
<a
href={watchUrl.toString()}
data-sveltekit-preload-data="off"
style="display: flex; justify-content:flex-start; position: absolute; width: 100%;"
><div class="bold" style="white-space: nowrap; overflow: hidden;text-overflow: ellipsis;">
{video.title}
</div>
<div class="tooltip bottom small">{video.title}</div>
</a>
<div style="margin-top: 1.4em;">
<a href={`/channel/${video.authorId}`}>{video.author}</a
>{#if !('publishedText' in video) && 'viewCountText' in video}
&nbsp;{video.viewCountText}{/if}
</div>
<nav class="no-margin">
{#if 'publishedText' in video}
<div class="max">
{cleanNumber(video.viewCount)}{video.publishedText}
</div>
<button class="transparent circle">
<i>arrow_drop_down</i>
<menu class="no-wrap">
<a href="#hide" on:click={hideVideo}>
{$_('hideVideo')}
</a>
<div class="divider"></div>
<ShareVideo {video} />
</menu>
</button>
{/if}
</nav>
</div>
</nav>
</div>
{/if}
<canvas id="canvas" style="display: none;"></canvas>
<div id="video-container" style="display: none;"></div>
+14 -6
View File
@@ -1,21 +1,29 @@
<script lang="ts">
import type { PlaylistPageVideo, Video, VideoBase } from './Api/model';
import type { Notification, PlaylistPageVideo, Video, VideoBase } from './Api/model';
import Thumbnail from './Thumbnail.svelte';
export let videos: VideoBase[] | Video[] | Notification[] | PlaylistPageVideo[] = [];
export let oneItemPerRow: boolean = false;
export let playlistId: string = '';
let hiddenVideos: string[] = [];
</script>
<div class="page right active">
<div class="space"></div>
<div class="grid">
{#each videos as video}
<div class={`s12 m${oneItemPerRow ? '12' : '6'} l${oneItemPerRow ? '12' : '2'}`}>
<article class="no-padding" style="height: 100%;">
<Thumbnail {video} {playlistId} />
</article>
</div>
{#if !hiddenVideos.includes(video.videoId)}
<div class={`s12 m${oneItemPerRow ? '12' : '6'} l${oneItemPerRow ? '12' : '2'}`}>
<article class="no-padding" style="height: 100%;">
<Thumbnail
on:videoHidden={() => (hiddenVideos = [...hiddenVideos, video.videoId])}
{video}
{playlistId}
/>
</article>
</div>
{/if}
{/each}
</div>
</div>
+2 -1
View File
@@ -11,6 +11,7 @@
"deleteAllHistory": "Delete all history",
"skipping": "Skipping",
"replies": "replies",
"hideVideo": "Hide video",
"syncParty": {
"userJoined": "User joined your watch party.",
"userLeft": "User left your watch party."
@@ -116,4 +117,4 @@
}
},
"subscribe": "Subscribe"
}
}
@@ -12,10 +12,10 @@
import type { Comments, PlaylistPage, PlaylistPageVideo } from '$lib/Api/model.js';
import Comment from '$lib/Comment.svelte';
import Player from '$lib/Player.svelte';
import ShareVideo from '$lib/ShareVideo.svelte';
import Thumbnail from '$lib/Thumbnail.svelte';
import { cleanNumber, getBestThumbnail, numberWithCommas, unsafeRandomItem } from '$lib/misc';
import type { PlayerEvents } from '$lib/player';
import { Capacitor } from '@capacitor/core';
import type { DataConnection } from 'peerjs';
import { onDestroy, onMount } from 'svelte';
import { _ } from 'svelte-i18n';
@@ -468,38 +468,8 @@
{$_('player.share.title')}
</div>
<menu class="no-wrap">
{#if !Capacitor.isNativePlatform()}
<a
class="row"
href="#copy"
on:click={async () =>
await navigator.clipboard.writeText(
`${location.origin}watch/${data.video.videoId}`
)}
>
<div class="min">{$_('player.share.materialiousLink')}</div></a
>
{/if}
<a
href="#copy"
class="row"
on:click={async () =>
await navigator.clipboard.writeText(
`https://redirect.invidious.io/watch?v=${data.video.videoId}`
)}
>
<div class="min">{$_('player.share.invidiousRedirect')}</div></a
><a
class="row"
href="#copy"
on:click={async () =>
await navigator.clipboard.writeText(
`https://www.youtube.com/watch?v=${data.video.videoId}`
)}
>
<div class="min">{$_('player.share.youtubeLink')}</div></a
></menu
></button
<ShareVideo video={data.video} />
</menu></button
>
{#if data.downloadOptions.length > 0}
<button class="border"