Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions Grayjay.Desktop.Web/src/components/PlaylistDetailView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Component, createMemo, createSignal, batch, Show } from 'solid-js';
import { type Component, createMemo, createSignal, createEffect, batch, Show } from 'solid-js';
import LoaderContainer from '../basics/loaders/LoaderContainer';
import NavigationBar from '../topbars/NavigationBar';
import styles from './index.module.css';
Expand All @@ -19,6 +19,7 @@ import iconDownload from '../../assets/icons/icon24_download.svg';
import iconTrash from '../../assets/icons/icon_trash.svg';
import UIOverlay from '../../state/UIOverlay';
import { IPlatformVideo } from '../../backend/models/content/IPlatformVideo';
import { HistoryBackend } from '../../backend/HistoryBackend';
import PlaylistItemView from '../PlaylistItemView';
import { Menus } from '../../Menus';
import { useNavigate } from '@solidjs/router';
Expand Down Expand Up @@ -99,6 +100,23 @@ const PlaylistDetailView: Component<PlaylistDetailViewProps> = (props) => {
});
}

const [positionMap$, setPositionMap] = createSignal<Record<string, number>>({});
createEffect(async () => {
const videos = props.videos;
if (!videos || videos.length === 0) return;
const entries = await Promise.all(
videos.map(async (v) => {
try {
const pos = await HistoryBackend.getHistoricalPosition(v.url);
return [v.url, pos] as [string, number];
} catch {
return [v.url, 0] as [string, number];
}
})
);
setPositionMap(Object.fromEntries(entries));
});

const [filterText$, setFilterText] = createSignal("");

const isEditable$ = createMemo(() => (filterText$()?.length ?? 0) == 0);
Expand Down Expand Up @@ -194,7 +212,8 @@ const PlaylistDetailView: Component<PlaylistDetailViewProps> = (props) => {
builder={(index, item, containerRef, dragControls) => {
const video = createMemo(() => item() as IPlatformVideo | undefined);
return (
<PlaylistItemView item={video()}
<PlaylistItemView item={video()}
position={video()?.url ? positionMap$()[video()!.url] : undefined}
isEditable={isEditable$()}
onRemove={() => {
const v = video();
Expand Down
15 changes: 13 additions & 2 deletions Grayjay.Desktop.Web/src/components/PlaylistItemView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styles from './index.module.css';
import iconDrag from '../../assets/icons/icon_drag.svg';
import iconClose from '../../assets/icons/icon24_close.svg';
import iconMore from '../../assets/icons/icon_button_more.svg';
import { proxyImage, toHumanNowDiffString, toHumanNumber } from '../../utility';
import { getVideoProgressPercentage, proxyImage, toHumanNowDiffString, toHumanNumber } from '../../utility';
import { DateTime } from 'luxon';
import IconButton from '../buttons/IconButton';

Expand All @@ -15,6 +15,7 @@ import { focusable } from '../../focusable';import { useFocus } from '../../Focu

interface PlaylistItemViewProps {
item?: IPlatformVideo;
position?: number;
onPlay?: () => void;
onRemove?: () => void;
onSettings?: (e: HTMLElement) => void;
Expand All @@ -41,7 +42,17 @@ const PlaylistItemView: Component<PlaylistItemViewProps> = (props) => {
<Show when={props.onDragStart && editable$() && focus?.isControllerMode() !== true} fallback={<div style="width: 12px"></div>}>
<img src={iconDrag} style="width: 24px; height: 24px; padding: 20px; cursor: pointer;" onMouseDown={(e) => props.onDragStart?.(e, e.target as HTMLElement)} />
</Show>
<img src={bestThumbnail$()?.url} style="width: auto; height: 100%; border-radius: 6px; aspect-ratio: 16/9; background-size: cover; cursor: pointer;" referrerPolicy='no-referrer' />
<div style="position: relative; height: 100%; aspect-ratio: 16/9; border-radius: 6px; overflow: hidden; flex-shrink: 0;">
<img src={bestThumbnail$()?.url} style="width: 100%; height: 100%; object-fit: cover; cursor: pointer;" referrerPolicy='no-referrer' />
<div style={{
"position": "absolute",
"bottom": "0px",
"left": "0px",
"background-color": "#019BE7",
"height": "3px",
"width": `${(props.position ?? 0) > 0 && (props.item?.duration ?? 0) > 0 ? getVideoProgressPercentage(props.position!, props.item!.duration!) : 0}%`
}} />
</div>
<div style="display: flex; flex-direction: column; flex-grow: 1; margin-left: 20px; margin-right: 20px; height: 100%; cursor: pointer;">
<div class={styles.itemTitle}>{props.item?.name}</div>
<div class={styles.authorBottomRow}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styles from './index.module.css';
import IconButton from '../../buttons/IconButton';
import more from '../../../assets/icons/more_horiz_FILL0_wght400_GRAD0_opsz24.svg';
import addToQueueIcon from '../../../assets/icons/icon_add_to_queue.svg';
import { dateFromAny, toHumanNowDiffString, toHumanNumber, toHumanTime } from '../../../utility';
import { dateFromAny, getVideoProgressPercentage, toHumanNowDiffString, toHumanNumber, toHumanTime } from '../../../utility';
import { DateTime } from 'luxon';
import { useNavigate } from '@solidjs/router';
import StateGlobal from '../../../state/StateGlobal';
Expand All @@ -16,6 +16,7 @@ import { focusable } from '../../../focusable';import { useFocus } from '../../.

interface VideoProps {
video?: IPlatformVideo;
position?: number;
onClick: () => void;
onSettings?: (element: HTMLDivElement, content: IPlatformVideo) => void;
onAddtoQueue?: (element: HTMLDivElement, content: IPlatformVideo) => void;
Expand All @@ -33,7 +34,8 @@ const VideoThumbnailView: Component<VideoProps> = (props) => {
})
var progress$ = createMemo(()=>{
let videoAny = props.video as any;
return (videoAny?.metadata?.position && props.video?.duration && props.video.duration > 0) ? (videoAny?.metadata?.position / props.video!.duration) : 0;
const position = props.position ?? videoAny?.metadata?.position;
return (position && props.video?.duration && props.video.duration > 0) ? getVideoProgressPercentage(position, props.video!.duration) / 100 : 0;
})

const navigate = useNavigate();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Component, Show, createMemo, createSignal, onCleanup } from 'solid-js'
import { Component, Show, createMemo, createSignal, createResource, onCleanup } from 'solid-js'

import styles from './index.module.css';
import { getBestThumbnail, positiveOrQ, proxyImage, resolutionOrUnknown, toHumanBitrate, toHumanBytesSize, toHumanBytesSpeed, toHumanNumber, toHumanTime } from '../../../utility';
import { getBestThumbnail, getVideoProgressPercentage, positiveOrQ, proxyImage, resolutionOrUnknown, toHumanBitrate, toHumanBytesSize, toHumanBytesSpeed, toHumanNumber, toHumanTime } from '../../../utility';
import { HistoryBackend } from '../../../backend/HistoryBackend';
import StateGlobal from '../../../state/StateGlobal';
import SubscribeButton from '../../buttons/SubscribeButton';
import settings from '../../../assets/icons/icon24_settings.svg';
Expand Down Expand Up @@ -55,6 +56,10 @@ const DownloadedView: Component<DownloadedViewProps> = (props) => {
}
}

const [position] = createResource(() => props.downloaded?.url, async (url) => {
try { return await HistoryBackend.getHistoricalPosition(url); } catch { return 0; }
});

let refMoreButton: HTMLDivElement | undefined;

return (
Expand All @@ -69,6 +74,16 @@ const DownloadedView: Component<DownloadedViewProps> = (props) => {
<div class={styles.badgeSize}>
{toHumanBytesSize(calcSize())}
</div>
<Show when={(position() ?? 0) > 0 && (props.downloaded?.videoDetails?.duration ?? 0) > 0}>
<div style={{
"position": "absolute",
"bottom": "0px",
"left": "0px",
"background-color": "#019BE7",
"height": "3px",
"width": `${getVideoProgressPercentage(position()!, props.downloaded!.videoDetails.duration!)}%`
}} />
</Show>
</div>
<div class={styles.title} onClick={navigate}>
{props.downloaded?.name}
Expand Down
21 changes: 20 additions & 1 deletion Grayjay.Desktop.Web/src/pages/Playlists/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createResource, type Component, Switch, Match, createSignal, batch, createMemo, Show, onMount } from 'solid-js';
import { createResource, type Component, Switch, Match, createSignal, batch, createMemo, createEffect, Show, onMount } from 'solid-js';
import NavigationBar from '../../components/topbars/NavigationBar';
import styles from './index.module.css';
import { WatchLaterBackend } from '../../backend/WatchLaterBackend';
Expand Down Expand Up @@ -29,6 +29,7 @@ import EmptyContentView from '../../components/EmptyContentView';
import { Menus } from '../../Menus';
import StateWebsocket from '../../state/StateWebsocket';
import { createResourceDefault } from '../../utility';
import { HistoryBackend } from '../../backend/HistoryBackend';
import LoaderGrid from '../../components/basics/loaders/LoaderGrid';
import InputText from '../../components/basics/inputs/InputText';
import Dropdown from '../../components/basics/inputs/Dropdown';
Expand Down Expand Up @@ -119,6 +120,23 @@ const PlaylistsPage: Component = () => {
});
}

const [watchLaterPositions$, setWatchLaterPositions] = createSignal<Record<string, number>>({});
createEffect(async () => {
const videos = video?.watchLater();
if (!videos || videos.length === 0) return;
const entries = await Promise.all(
videos.map(async (v) => {
try {
const pos = await HistoryBackend.getHistoricalPosition(v.url);
return [v.url, pos] as [string, number];
} catch {
return [v.url, 0] as [string, number];
}
})
);
setWatchLaterPositions(Object.fromEntries(entries));
});

const [filterText, setFilterText] = createSignal("");
const [sortBy, setSortBy] = createSignal(0);

Expand Down Expand Up @@ -231,6 +249,7 @@ const PlaylistsPage: Component = () => {
}}
builder={(index, item) =>
<VideoThumbnailView video={item() as IPlatformVideo}
position={(item() as IPlatformVideo)?.url ? watchLaterPositions$()[(item() as IPlatformVideo).url] : undefined}
onClick={() => {
const queue = video?.watchLater();
if (!queue) {
Expand Down