Merge pull request #84 from WardPearce/update/close-minor-issues

Update/close minor issues
This commit is contained in:
Ward
2024-04-09 16:38:28 +12:00
committed by GitHub
8 changed files with 303 additions and 161 deletions
+3
View File
@@ -123,6 +123,9 @@
event.detail.currentTime >= segment.startTime &&
event.detail.currentTime <= segment.endTime
) {
if (Math.round(player.currentTime) >= Math.round(player.duration)) {
return;
}
categoryBeingSkipped = segment.category;
player.currentTime = segment.endTime + 1;
ui('#sponsorblock-alert');
+36 -2
View File
@@ -24,10 +24,12 @@
interfaceSearchSuggestions,
playerAlwaysLoop,
playerAutoPlay,
playerAutoplayNextByDefault,
playerDash,
playerListenByDefault,
playerProxyVideos,
playerSavePlaybackPosition,
playerTheatreModeByDefault,
returnYTDislikesInstance,
returnYtDislikes,
sponsorBlock,
@@ -405,7 +407,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Autoplay</div>
<div>Autoplay video</div>
</div>
<label class="switch">
<input
@@ -421,7 +423,7 @@
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Always loop</div>
<div>Always loop video</div>
</div>
<label class="switch">
<input
@@ -482,6 +484,38 @@
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Theatre mode by default</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerTheatreModeByDefault}
on:click={() => playerTheatreModeByDefault.set(!$playerTheatreModeByDefault)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
<div>Autoplay next by default</div>
</div>
<label class="switch">
<input
type="checkbox"
bind:checked={$playerAutoplayNextByDefault}
on:click={() => playerAutoplayNextByDefault.set(!$playerAutoplayNextByDefault)}
/>
<span></span>
</label>
</nav>
</div>
<div class="field no-margin">
<nav class="no-padding">
<div class="max">
@@ -100,26 +100,34 @@
</div>
<div class="tabs left-align scroll">
<a class:active={tab === 'videos'} on:click={() => changeTab('videos')} href={`#video`}>
<i>movie</i>
<span>Videos</span>
</a>
<a class:active={tab === 'shorts'} on:click={() => changeTab('shorts')} href={`#short`}>
<i>smartphone</i>
<span>Shorts</span>
</a>
<a class:active={tab === 'streams'} on:click={() => changeTab('streams')} href={`#stream`}>
<i>stream</i>
<span>Streams</span>
</a>
<a
class:active={tab === 'playlists'}
on:click={() => changeTab('playlists')}
href={`#playlist`}
>
<i>playlist_add_check</i>
<span>Playlists</span>
</a>
{#if data.channel.tabs.includes('videos')}
<a class:active={tab === 'videos'} on:click={() => changeTab('videos')} href={`#video`}>
<i>movie</i>
<span>Videos</span>
</a>
{/if}
{#if data.channel.tabs.includes('shorts')}
<a class:active={tab === 'shorts'} on:click={() => changeTab('shorts')} href={`#short`}>
<i>smartphone</i>
<span>Shorts</span>
</a>
{/if}
{#if data.channel.tabs.includes('streams')}
<a class:active={tab === 'streams'} on:click={() => changeTab('streams')} href={`#stream`}>
<i>stream</i>
<span>Streams</span>
</a>
{/if}
{#if data.channel.tabs.includes('playlists')}
<a
class:active={tab === 'playlists'}
on:click={() => changeTab('playlists')}
href={`#playlist`}
>
<i>playlist_add_check</i>
<span>Playlists</span>
</a>
{/if}
</div>
</div>
@@ -1,7 +1,7 @@
<script lang="ts">
import { page } from '$app/stores';
import { getSearch } from '$lib/Api';
import ChannelThumbnail from '$lib/ChannelThumbnail.svelte';
import PageLoading from '$lib/PageLoading.svelte';
import PlaylistThumbnail from '$lib/PlaylistThumbnail.svelte';
import Thumbnail from '$lib/Thumbnail.svelte';
import InfiniteLoading, { type InfiniteEvent } from 'svelte-infinite-loading';
@@ -15,9 +15,11 @@
activePage.set(null);
function changeType(type: string) {
$page.url.searchParams.set('type', type);
document.location.href = $page.url.href;
async function changeType(type: 'playlist' | 'all' | 'video' | 'channel') {
data.searchType = type;
currentPage = 1;
search = [];
search = await getSearch(data.slug, { type: type });
}
async function loadMore(event: InfiniteEvent) {
@@ -38,14 +40,18 @@
<div class="space" style="margin-bottom: 1em;">
<div class="tabs left-align min scroll">
<a class:active={data.searchType === 'all'} href="#all" on:click={() => changeType('all')}>
<a
class:active={data.searchType === 'all'}
href="#all"
on:click={async () => changeType('all')}
>
<i>home</i>
<span>All</span>
</a>
<a
class:active={data.searchType === 'video'}
href="#videos"
on:click={() => changeType('video')}
on:click={async () => changeType('video')}
>
<i>movie</i>
<span>Videos</span>
@@ -53,7 +59,7 @@
<a
class:active={data.searchType === 'playlist'}
href="#playlists"
on:click={() => changeType('playlist')}
on:click={async () => changeType('playlist')}
>
<i>playlist_add_check</i>
<span>Playlists</span>
@@ -61,7 +67,7 @@
<a
class:active={data.searchType === 'channel'}
href="#channels"
on:click={() => changeType('channel')}
on:click={async () => changeType('channel')}
>
<i>person</i>
<span>Channels</span>
@@ -69,25 +75,29 @@
</div>
</div>
<div class="page right active">
<div class="space"></div>
<div class="grid">
{#each search as item}
<div class="s12 m6 l2">
{#key data.search}
<article class="no-padding" style="height: 100%;">
{#if item.type === 'video'}
<Thumbnail video={item} />
{:else if item.type === 'channel'}
<ChannelThumbnail channel={item} />
{:else if item.type === 'playlist'}
<PlaylistThumbnail playlist={item} />
{/if}
</article>
{/key}
</div>
{/each}
{#if search.length > 0}
<div class="page right active">
<div class="space"></div>
<div class="grid">
{#each search as item}
<div class="s12 m6 l2">
{#key item}
<article class="no-padding" style="height: 100%;">
{#if item.type === 'video'}
<Thumbnail video={item} />
{:else if item.type === 'channel'}
<ChannelThumbnail channel={item} />
{:else if item.type === 'playlist'}
<PlaylistThumbnail playlist={item} />
{/if}
</article>
{/key}
</div>
{/each}
</div>
</div>
</div>
{:else}
<PageLoading />
{/if}
<InfiniteLoading on:infinite={loadMore} />
@@ -7,7 +7,7 @@
export let data;
let currentPage = 1;
$: videos = [...data.feed.videos, ...data.feed.notifications];
$: videos = data.feed.notifications;
activePage.set('subscriptions');
+182 -111
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import { goto } from '$app/navigation';
import {
addPlaylistVideo,
deleteUnsubscribe,
@@ -21,7 +22,9 @@
import {
activePage,
auth,
playerAutoplayNextByDefault,
playerListenByDefault,
playerTheatreModeByDefault,
syncPartyConnections,
syncPartyPeer
} from '../../../store';
@@ -35,6 +38,8 @@
let playlistVideos: PlaylistPageVideo[] = [];
let playlist: PlaylistPage | null = null;
let theatreMode = get(playerTheatreModeByDefault);
let audioMode = get(playerListenByDefault);
let currentTime: number;
let seekTo: (time: number) => void;
@@ -65,6 +70,16 @@
});
});
player.addEventListener('auto-play-fail', () => {
conn.send({
events: [
{
type: 'pause'
}
]
} as PlayerEvents);
});
player.addEventListener('auto-play', () => {
conn.send({
events: [
@@ -151,6 +166,16 @@
});
}
player.addEventListener('end', () => {
if ($playerAutoplayNextByDefault && !playlist) {
goto(`/watch/${data.video.recommendedVideos[0].videoId}`);
}
if (data.playlistId) {
setTimeout(goToCurrentPlaylistItem, 1000);
}
});
if (!data.playlistId) return;
for (let page = 1; page < Infinity; page++) {
@@ -169,6 +194,10 @@
);
}
goToCurrentPlaylistItem();
});
function goToCurrentPlaylistItem() {
const playlistCurrentVideo = document.getElementById(data.video.videoId);
const playlistScrollable = document.getElementById('playlist');
@@ -176,7 +205,7 @@
playlistScrollable.scrollTop =
playlistCurrentVideo.offsetTop - playlistScrollable.offsetTop - 200;
}
});
}
async function addVideoToPlaylist(playlistId: string) {
await addPlaylistVideo(playlistId, data.video.videoId);
@@ -207,11 +236,15 @@
data.subscribed = !data.subscribed;
}
async function toggleTheatreMode() {
theatreMode = !theatreMode;
}
</script>
{#if data}
<div class="grid">
<div class="s12 m12 l10">
<div class={`s12 m12 l${theatreMode ? '12' : '10'}`}>
{#key data.video.videoId}
<Player
{data}
@@ -275,79 +308,90 @@
</button>
</nav>
{/if}
<button on:click={() => (audioMode = !audioMode)} class:border={!audioMode}>
<i>headphones</i>
</button>
<button class="border"
><i>share</i>
<menu class="no-wrap">
<a
class="row"
href="#copy"
on:click={async () =>
await navigator.clipboard.writeText(
`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}/watch/${data.video.videoId}`
)}
>
<div class="min">Copy Materialious link</div></a
><a
href="#copy"
class="row"
on:click={async () =>
await navigator.clipboard.writeText(
`https://redirect.invidious.io/watch?v=${data.video.videoId}`
)}
>
<div class="min">Copy Invidious redirect link</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">Copy Youtube link</div></a
></menu
></button
>
{#if data.downloadOptions.length > 0}
<div>
<button on:click={() => (audioMode = !audioMode)} class:border={!audioMode}>
<i>headphones</i>
<div class="tooltip">Audio only</div>
</button>
<button on:click={toggleTheatreMode} class="m l" class:border={!theatreMode}>
<i>width_wide</i>
<div class="tooltip">Theatre mode</div>
</button>
<button class="border"
><i>download</i>
><i>share</i>
<div class="tooltip">Share</div>
<menu class="no-wrap">
{#each data.downloadOptions as download}
<a class="row" href={download.url} target="_blank" rel="noopener noreferrer"
>{download.title}</a
>
{/each}
</menu></button
<a
class="row"
href="#copy"
on:click={async () =>
await navigator.clipboard.writeText(
`${import.meta.env.VITE_DEFAULT_FRONTEND_URL}/watch/${data.video.videoId}`
)}
>
<div class="min">Copy Materialious link</div></a
><a
href="#copy"
class="row"
on:click={async () =>
await navigator.clipboard.writeText(
`https://redirect.invidious.io/watch?v=${data.video.videoId}`
)}
>
<div class="min">Copy Invidious redirect link</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">Copy Youtube link</div></a
></menu
></button
>
{/if}
{#if data.personalPlaylists}
<button class="border">
<i>add</i>
<menu>
{#each data.personalPlaylists as personalPlaylist}
<a
href="#add"
on:click={async () => await addVideoToPlaylist(personalPlaylist.playlistId)}
>{personalPlaylist.title}
</a>
{/each}
</menu>
</button>
{:else}
<button disabled class="border no-margin">
<i>add</i>
<div class="tooltip">
{#if $auth}
No playlists
{:else}
Login required
{/if}
</div>
</button>
{/if}
{#if data.downloadOptions.length > 0}
<button class="border"
><i>download</i>
<div class="tooltip">Download</div>
<menu class="no-wrap">
{#each data.downloadOptions as download}
<a class="row" href={download.url} target="_blank" rel="noopener noreferrer"
>{download.title}</a
>
{/each}
</menu></button
>
{/if}
{#if data.personalPlaylists}
<button class="border">
<i>add</i>
<div class="tooltip">Add to playlist</div>
<menu>
{#each data.personalPlaylists as personalPlaylist}
<a
href="#add"
on:click={async () => await addVideoToPlaylist(personalPlaylist.playlistId)}
>{personalPlaylist.title}
</a>
{/each}
</menu>
</button>
{:else}
<button disabled class="border no-margin">
<i>add</i>
<div class="tooltip">
{#if $auth}
No playlists
{:else}
Login required
{/if}
</div>
</button>
{/if}
</div>
</div>
</div>
@@ -370,10 +414,7 @@
{#if data.content.timestamps.length > 0}
<h6 style="margin-bottom: .3em;">Chapters</h6>
{#each data.content.timestamps as timestamp}
<button
on:click={() => seekTo(timestamp.time)}
class="timestamps"
class:primary={timestamp.time <= currentTime}
<button on:click={() => seekTo(timestamp.time)} class="timestamps"
>{timestamp.timePretty}
{#if !timestamp.title.startsWith('-')}
-
@@ -400,41 +441,47 @@
<h6>Unable to load comments</h6>
{/if}
</div>
<div class="s12 m12 l2">
{#if !data.playlistId}
{#if data.video.recommendedVideos}
{#each data.video.recommendedVideos as recommendedVideo}
<article class="no-padding">
{#key recommendedVideo.videoId}
<Thumbnail video={recommendedVideo} />
{/key}
{#if !theatreMode}
<div class="s12 m12 l2">
{#if !data.playlistId}
{#if data.video.recommendedVideos}
{#each data.video.recommendedVideos as recommendedVideo}
<article class="no-padding">
{#key recommendedVideo.videoId}
<Thumbnail video={recommendedVideo} />
{/key}
</article>
{/each}
{/if}
{:else if playlist}
<article
style="height: 75vh; position: relative;"
id="playlist"
class="scroll no-padding"
>
<article class="no-elevate" style="position: sticky; top: 0; z-index: 3;">
<h6>{playlist.title}</h6>
<p>{cleanNumber(playlist.viewCount)} views • {playlist.videoCount} videos</p>
<p><a href={`/channel/${playlist.authorId}`}>{playlist.author}</a></p>
<div class="divider"></div>
</article>
{/each}
{/if}
{:else if playlist}
<article style="height: 75vh; position: relative;" id="playlist" class="scroll no-padding">
<article class="no-elevate" style="position: sticky; top: 0; z-index: 3;">
<h6>{playlist.title}</h6>
<p>{cleanNumber(playlist.viewCount)} views • {playlist.videoCount} videos</p>
<p><a href={`/channel/${playlist.authorId}`}>{playlist.author}</a></p>
<div class="divider"></div>
<div class="space"></div>
{#each playlistVideos as playlistVideo}
<article
class="no-padding primary-border"
style="margin: .7em;"
id={playlistVideo.videoId}
class:border={playlistVideo.videoId === data.video.videoId}
>
<Thumbnail video={playlistVideo} playlistId={data.playlistId} />
</article>
{/each}
</article>
<div class="space"></div>
{#each playlistVideos as playlistVideo}
<article
class="no-padding primary-border"
style="margin: .7em;"
id={playlistVideo.videoId}
class:border={playlistVideo.videoId === data.video.videoId}
>
<Thumbnail video={playlistVideo} playlistId={data.playlistId} />
</article>
{/each}
</article>
{/if}
</div>
{/if}
</div>
{/if}
</div>
{:else}
<PageLoading />
@@ -453,10 +500,16 @@
margin-left: 0;
margin-bottom: 0.4em;
display: block;
background-color: var(--secondary-container);
padding: 0;
text-align: left;
background-color: transparent;
color: var(--on-secondary-container);
}
.timestamps:hover {
padding: 0 0.5em;
}
.video-actions {
display: flex;
align-items: center;
@@ -469,7 +522,25 @@
@media screen and (max-width: 1000px) {
.video-actions {
justify-content: flex-start;
align-items: flex-start;
flex-direction: column;
}
}
@media screen and (max-width: 1000px) {
.video-actions > div {
margin-top: 1em;
}
}
@media screen and (max-width: 1000px) {
menu {
position: fixed;
top: 50%;
left: 50%;
width: 100%;
transform: translate(-50%, 50%);
background-color: var(--surface-variant);
}
}
+2
View File
@@ -15,6 +15,8 @@ export const playerProxyVideos = persisted("proxyVideos", false);
export const playerListenByDefault = persisted("listenByDefault", false);
export const playerSavePlaybackPosition = persisted("savePlaybackPosition", true);
export const playerDash = persisted("dashEnabled", false);
export const playerTheatreModeByDefault = persisted("theatreModeByDefault", false);
export const playerAutoplayNextByDefault = persisted("autoplayNextByDefault", false);
export const returnYtDislikes = persisted("returnYtDislikes", true);
+14
View File
@@ -2,6 +2,20 @@
padding: .1em .4em;
}
.vds-chapter-radio-label {
word-wrap: break-word !important;
overflow-wrap: break-word !important;
white-space: normal !important;
}
.vds-chapter-radio-content {
max-width: 200px !important;
}
.vds-chapter-radio {
align-items: start !important;
}
@media screen and (max-width: 580px) {
main {
padding-left: .1em !important;