Started channel page

This commit is contained in:
WardPearce
2024-03-08 17:54:29 +13:00
parent 4c7c7f2540
commit fcb481b736
6 changed files with 89 additions and 19 deletions
+6 -1
View File
@@ -1,6 +1,6 @@
import { get } from 'svelte/store';
import { invidiousInstance, returnYTDislikesInstance } from '../../store';
import type { Comments, ReturnYTDislikes, Video, VideoPlay } from './model';
import type { Channel, Comments, ReturnYTDislikes, Video, VideoPlay } from './model';
export function buildPath(path: string): string {
return `${get(invidiousInstance)}/api/v1/${path}`;
@@ -26,4 +26,9 @@ export async function getComments(videoId: string, parameters: { sortBy: "top" |
path.search = new URLSearchParams(parameters).toString();
const resp = await fetch(path);
return await resp.json();
}
export async function getChannel(channelId: string): Promise<Channel> {
const resp = await fetch(buildPath(`channels/${channelId}`));
return await resp.json();
}
+21 -8
View File
@@ -72,12 +72,6 @@ export interface Captions {
url: string;
};
export interface AuthorThumbnails {
url: string;
width: string;
height: string;
}
export interface VideoPlay extends Video {
keywords: string[];
likeCount: number;
@@ -94,7 +88,7 @@ export interface VideoPlay extends Video {
adaptiveFormats: AdaptiveFormats[];
formatStreams: FormatStreams[];
recommendedVideos: VideoBase[];
authorThumbnails: AuthorThumbnails[];
authorThumbnails: Image[];
captions: Captions[];
}
@@ -110,7 +104,7 @@ export interface ReturnYTDislikes {
export interface Comment {
author: string;
authorThumbnails: AuthorThumbnails[];
authorThumbnails: Image[];
authorID: string;
authorUrl: string;
isEdited: boolean;
@@ -136,4 +130,23 @@ export interface Comments {
videoId: string;
continuation?: string;
comments: Comment[];
}
export interface Channel {
author: string;
authorId: string;
authorUrl: string;
authorVerified: boolean;
authorBanners: Image[];
authorThumbnails: Image[];
subCount: number;
totalViews: number;
joined: number;
autoGenerated: boolean;
isFamilyFriendly: boolean;
description: string;
descriptionHml: string;
allowedRegions: string[];
tabs: string[];
latestVideos: Video[];
}
+6
View File
@@ -1,7 +1,13 @@
import humanNumber from "human-number";
export function truncate(value: string, maxLength: number = 50): string {
return value.length > maxLength ? `${value.substring(0, maxLength)}...` : value;
}
export function numberWithCommas(number: number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
export function cleanNumber(number: number): string {
return humanNumber(number, (number: number) => Number.parseFloat(number.toString()).toFixed(1));
}
@@ -0,0 +1,44 @@
<script lang="ts">
import { cleanNumber } from '$lib/misc';
import Thumbnail from '$lib/Thumbnail.svelte';
export let data;
</script>
<div class="padding">
{#if data.channel.authorBanners.length > 0}
<img src={data.channel.authorBanners[0].url} width="100%" alt="Channel banner" />
{/if}
<div class="description">
<img
style="margin-right: 1em;"
class="circle extra m l"
src={data.channel.authorThumbnails[5].url}
alt="Channel profile"
/>
<div>
<h2>{data.channel.author}</h2>
<p>{cleanNumber(data.channel.subCount)} subscribers</p>
<p style="width: 60vw;">{data.channel.description}</p>
</div>
<button class="inverse-surface large">Subscribe</button>
</div>
<div class="divider"></div>
<div class="grid padding">
{#each data.channel.latestVideos as video}
<div class="s12 m6 l2">
<Thumbnail {video} />
</div>
{/each}
</div>
</div>
<style>
.description {
display: flex;
padding: 1em 0;
justify-content: center;
}
</style>
@@ -0,0 +1,7 @@
import { getChannel } from '$lib/Api/index.js';
export async function load({ params }) {
return {
channel: await getChannel(params.slug)
};
}
@@ -1,22 +1,17 @@
<script lang="ts">
import humanNumber from 'human-number';
import { get } from 'svelte/store';
import Plyr from 'plyr';
import 'plyr/dist/plyr.css';
import Thumbnail from '$lib/Thumbnail.svelte';
import { numberWithCommas } from '$lib/misc.js';
import { cleanNumber, numberWithCommas } from '$lib/misc.js';
import { onMount } from 'svelte';
import { invidiousInstance } from '../../../store';
export let data;
const cleanRound = (number: number) => Number.parseFloat(number.toString()).toFixed(1);
$: video = data.video;
let player;
onMount(() => {
player = new Plyr('#player');
@@ -65,11 +60,11 @@
<nav class="no-space m l">
<button style="cursor: default;" class="border left-round">
<i class="small">thumb_up</i>
<span>{humanNumber(data.returnYTDislikes.likes, cleanRound)}</span>
<span>{cleanNumber(data.returnYTDislikes.likes)}</span>
</button>
<button style="cursor: default;" class="border right-round">
<i class="small">thumb_down_alt</i>
<span>{humanNumber(data.returnYTDislikes.dislikes, cleanRound)}</span>
<span>{cleanNumber(data.returnYTDislikes.dislikes)}</span>
</button>
</nav>
<button class="border m l" data-ui="#share"
@@ -85,11 +80,11 @@
<nav class="no-space s">
<button style="cursor: default;" class="border left-round">
<i class="small">thumb_up</i>
<span>{humanNumber(data.returnYTDislikes.likes, cleanRound)}</span>
<span>{cleanNumber(data.returnYTDislikes.likes)}</span>
</button>
<button style="cursor: default;" class="border right-round">
<i class="small">thumb_down_alt</i>
<span>{humanNumber(data.returnYTDislikes.dislikes, cleanRound)}</span>
<span>{cleanNumber(data.returnYTDislikes.dislikes)}</span>
</button>
</nav>