-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a007beb
commit b2a6a8b
Showing
6 changed files
with
341 additions
and
1 deletion.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
packages/web-client/src/routes/(feed)/(splash)/up-down/+layout.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<script lang="ts"> | ||
import HotOrNotLayout from '$components/layout/HotOrNotLayout.svelte' | ||
</script> | ||
|
||
<svelte:head> | ||
<title>Up Down | Hot or Not</title> | ||
</svelte:head> | ||
|
||
<HotOrNotLayout> | ||
<svelte:fragment slot="content"> | ||
<slot /> | ||
</svelte:fragment> | ||
</HotOrNotLayout> |
25 changes: 25 additions & 0 deletions
25
packages/web-client/src/routes/(feed)/(splash)/up-down/+page.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
export const ssr = false | ||
|
||
import type { PageLoad } from './$types' | ||
import { redirect } from '@sveltejs/kit' | ||
import { postCache } from '$lib/helpers/backend' | ||
|
||
export const load: PageLoad = async ({ fetch }) => { | ||
const res = await postCache( | ||
fetch, | ||
).get_top_posts_aggregated_from_canisters_on_this_network_for_hot_or_not_feed( | ||
BigInt(0), | ||
BigInt(1), | ||
) | ||
|
||
if ('Ok' in res && res.Ok[0]) { | ||
throw redirect( | ||
307, | ||
`/up-down/${res.Ok[0].publisher_canister_id.toText()}@${ | ||
res.Ok[0].post_id | ||
}`, | ||
) | ||
} else { | ||
throw redirect(307, '/up-down/no-videos') | ||
} | ||
} |
226 changes: 226 additions & 0 deletions
226
packages/web-client/src/routes/(feed)/(splash)/up-down/[id=videoId]/+page.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
<script lang="ts"> | ||
import { beforeNavigate } from '$app/navigation' | ||
import Button from '$components/button/Button.svelte' | ||
import PlayerLayout from '$components/layout/PlayerLayout.svelte' | ||
import HotOrNotVote from '$components/hot-or-not/HotOrNotVote.svelte' | ||
import VideoPlayer from '$components/video/VideoPlayer.svelte' | ||
import { | ||
getHotOrNotPosts, | ||
updatePostInWatchHistory, | ||
type PostPopulated, | ||
} from '$lib/helpers/feed' | ||
import { updateURL } from '$lib/utils/feedUrl' | ||
import Log from '$lib/utils/Log' | ||
import { handleParams } from '$lib/utils/params' | ||
import { joinArrayUniquely, updateMetadata } from '$lib/utils/video' | ||
import { hotOrNotFeedVideos, playerState } from '$stores/playerState' | ||
import { hideSplashScreen } from '$stores/popups' | ||
import Hls from 'hls.js/dist/hls.min.js' | ||
import { onMount, tick } from 'svelte' | ||
import 'swiper/css' | ||
import { Swiper, SwiperSlide } from 'swiper/svelte' | ||
import type { PageData } from './$types' | ||
import Icon from '$components/icon/Icon.svelte' | ||
import UpDownVote from '$components/up-down/UpDownVote.svelte' | ||
export let data: PageData | ||
const fetchCount = 25 | ||
const fetchWhenVideosLeft = 10 | ||
const keepVideosLoadedCount: number = 3 | ||
let videos: PostPopulated[] = [] | ||
let currentVideoIndex = 0 | ||
let lastWatchedVideoIndex = -1 | ||
let noMoreVideos = false | ||
let loading = false | ||
let fetchedVideosCount = 0 | ||
let loadTimeout: ReturnType<typeof setTimeout> | undefined = undefined | ||
let errorCount = 0 | ||
let showError = false | ||
async function fetchNextVideos(force = false) { | ||
// console.log( | ||
// `to fetch: ${!noMoreVideos} && ${ | ||
// videos.length | ||
// } - ${currentVideoIndex}<${fetchCount}, errorCount: ${errorCount}` | ||
// ); | ||
if ( | ||
!noMoreVideos && | ||
(force || videos.length - currentVideoIndex < fetchWhenVideosLeft) | ||
) { | ||
try { | ||
Log('info', 'Fetching videos for feed', { | ||
res: 'fetching from ' + fetchedVideosCount, | ||
source: 'hotOrNot.fetchNextVideos', | ||
}) | ||
loading = true | ||
const res = await getHotOrNotPosts(fetchedVideosCount, fetchCount) | ||
if (res.error) { | ||
if (errorCount < 4) { | ||
loadTimeout = setTimeout(() => { | ||
errorCount++ | ||
fetchNextVideos() | ||
}, 5000) | ||
} else { | ||
clearTimeout(loadTimeout) | ||
showError = true | ||
loading = false | ||
} | ||
return | ||
} else { | ||
errorCount = 0 | ||
if (loadTimeout) clearTimeout(loadTimeout) | ||
} | ||
fetchedVideosCount = res.from | ||
videos = joinArrayUniquely(videos, res.posts) | ||
if (res.noMorePosts) { | ||
noMoreVideos = res.noMorePosts | ||
// const watchedVideos = await getWatchedVideosFromCache('watch-hon') | ||
// videos = joinArrayUniquely(videos, watchedVideos) | ||
} else if (!res.noMorePosts && res.posts.length < fetchCount - 10) { | ||
fetchNextVideos(true) | ||
} | ||
await tick() | ||
loading = false | ||
Log('info', 'Fetched videos for feed', { | ||
noMoreVideos, | ||
source: 'hotOrNot.fetchNextVideos', | ||
}) | ||
} catch (e) { | ||
Log('error', 'Could not fetch videos for feed', { | ||
error: e, | ||
noMoreVideos, | ||
source: 'hotOrNot.fetchNextVideos', | ||
}) | ||
loading = false | ||
} | ||
} | ||
} | ||
async function handleChange(e: CustomEvent) { | ||
lastWatchedVideoIndex = currentVideoIndex | ||
const newIndex = e.detail[0].realIndex | ||
currentVideoIndex = newIndex | ||
fetchNextVideos() | ||
updateURL(videos[currentVideoIndex]) | ||
updateMetadata(videos[currentVideoIndex]) | ||
} | ||
async function handleUnavailableVideo(index: number) { | ||
videos.splice(index, 1) | ||
videos = videos | ||
} | ||
onMount(async () => { | ||
updateURL() | ||
$playerState.initialized = false | ||
$playerState.muted = true | ||
$playerState.visible = true | ||
if (data?.post) { | ||
videos = [data.post, ...videos] | ||
updatePostInWatchHistory('watch-hon', data.post) | ||
} else if ($hotOrNotFeedVideos.length) { | ||
videos = $hotOrNotFeedVideos | ||
$hotOrNotFeedVideos = [] | ||
} | ||
await tick() | ||
fetchNextVideos() | ||
handleParams() | ||
}) | ||
beforeNavigate(() => { | ||
$playerState.visible = false | ||
$playerState.muted = true | ||
videos.length > 2 && hotOrNotFeedVideos.set(videos.slice(currentVideoIndex)) | ||
}) | ||
</script> | ||
|
||
<svelte:head> | ||
<title>Up Down | Hot or Not</title> | ||
</svelte:head> | ||
|
||
<Swiper | ||
direction={'vertical'} | ||
observer | ||
cssMode | ||
slidesPerView={1} | ||
on:slideChange={handleChange} | ||
spaceBetween={300} | ||
class="h-full w-full"> | ||
{#each videos as post, i (i)} | ||
<SwiperSlide | ||
class="flex h-full w-full snap-always items-center justify-center"> | ||
{#if currentVideoIndex - 2 < i && currentVideoIndex + keepVideosLoadedCount > i} | ||
<PlayerLayout | ||
bind:post | ||
index={i} | ||
source="hon_feed" | ||
watchHistoryDb="watch-hon" | ||
showWalletLink | ||
showReportButton | ||
let:recordView | ||
let:updateStats> | ||
<VideoPlayer | ||
on:watchComplete={updateStats} | ||
on:loaded={() => hideSplashScreen(500)} | ||
on:watchedPercentage={({ detail }) => recordView(detail)} | ||
on:videoUnavailable={() => handleUnavailableVideo(i)} | ||
index={i} | ||
playFormat="hls" | ||
{Hls} | ||
inView={i == currentVideoIndex && $playerState.visible} | ||
uid={post.video_uid} /> | ||
|
||
<svelte:fragment slot="hotOrNot"> | ||
<UpDownVote /> | ||
</svelte:fragment> | ||
</PlayerLayout> | ||
{/if} | ||
</SwiperSlide> | ||
{/each} | ||
{#if showError} | ||
<SwiperSlide class="flex h-full w-full items-center justify-center"> | ||
<div | ||
class="relative flex h-full w-full flex-col items-center justify-center space-y-8 px-8"> | ||
<div class="text-center text-lg font-bold"> | ||
Error loading posts. Please, refresh the page. | ||
</div> | ||
<Button | ||
type="primary" | ||
on:click={(e) => e.preventDefault()} | ||
href="/hotornot"> | ||
Clear here to refresh | ||
</Button> | ||
</div> | ||
</SwiperSlide> | ||
{/if} | ||
{#if loading} | ||
<SwiperSlide class="flex h-full w-full items-center justify-center"> | ||
<div | ||
class="relative flex h-full w-full flex-col items-center justify-center space-y-8 px-8"> | ||
<div class="text-center text-lg font-bold">Loading</div> | ||
</div> | ||
</SwiperSlide> | ||
{/if} | ||
{#if noMoreVideos} | ||
<SwiperSlide class="relative h-full w-full items-center justify-center"> | ||
<div | ||
class="absolute flex h-full w-full flex-col items-center justify-center space-y-8 bg-black/50 px-8"> | ||
<Icon name="votes-graphics" class="w-56" /> | ||
<div class="text-center text-lg font-bold"> | ||
There are no more videos to vote on | ||
</div> | ||
<div class="absolute inset-x-0 bottom-20 z-[-1] max-h-48"> | ||
<HotOrNotVote disabled /> | ||
</div> | ||
</div> | ||
</SwiperSlide> | ||
{/if} | ||
</Swiper> |
54 changes: 54 additions & 0 deletions
54
packages/web-client/src/routes/(feed)/(splash)/up-down/[id=videoId]/+page.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
export const ssr = false | ||
export const prerender = false | ||
|
||
import { Principal } from '@dfinity/principal' | ||
import type { PageLoad } from './$types' | ||
import type { PostPopulated } from '$lib/helpers/feed' | ||
import { individualUser } from '$lib/helpers/backend' | ||
import Log from '$lib/utils/Log' | ||
|
||
export const load: PageLoad = async ({ params, fetch }) => { | ||
try { | ||
const id = params.id.split('@') | ||
const postId = BigInt(Number(id[1])) | ||
const principal = Principal.from(id[0]) | ||
let cachedPost: PostPopulated | undefined = undefined | ||
|
||
try { | ||
const { idb } = await import('$lib/idb') | ||
cachedPost = await idb.get('watch', params.id) | ||
} catch (e) { | ||
Log('error', 'Error while accessing IDB', { | ||
error: e, | ||
from: 'feedLoad', | ||
type: 'idb', | ||
}) | ||
cachedPost = undefined | ||
} | ||
|
||
if (cachedPost) { | ||
return { post: cachedPost } | ||
} else { | ||
const r = await individualUser( | ||
principal, | ||
fetch, | ||
).get_individual_post_details_by_id(postId) | ||
if (r.video_uid) { | ||
return { | ||
post: { | ||
...r, | ||
publisher_canister_id: id[0], | ||
created_by_user_principal_id: | ||
r.created_by_user_principal_id.toText(), | ||
post_id: postId, | ||
score: BigInt(0), | ||
} as PostPopulated, | ||
} | ||
} else { | ||
return | ||
} | ||
} | ||
} catch (e) { | ||
return | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
packages/web-client/src/routes/(feed)/(splash)/up-down/no-videos/+page.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<script lang="ts"> | ||
import HotOrNotVote from '$components/hot-or-not/HotOrNotVote.svelte' | ||
import Icon from '$components/icon/Icon.svelte' | ||
import { hideSplashScreen } from '$stores/popups' | ||
import { onMount, tick } from 'svelte' | ||
onMount(async () => { | ||
await tick() | ||
hideSplashScreen(500) | ||
}) | ||
</script> | ||
|
||
<div | ||
class="absolute flex h-full w-full flex-col items-center justify-center space-y-8 bg-black/50 px-8"> | ||
<Icon name="votes-graphics" class="w-56" /> | ||
<div class="text-center text-lg font-bold"> | ||
There are no videos to vote on | ||
</div> | ||
<div class="absolute inset-x-0 bottom-20 z-[-1] max-h-48"> | ||
<HotOrNotVote disabled /> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters