diff --git a/.github/workflows/prod-vite.yml b/.github/workflows/prod-vite.yml index c3af543e..2feef2bf 100644 --- a/.github/workflows/prod-vite.yml +++ b/.github/workflows/prod-vite.yml @@ -13,23 +13,20 @@ jobs: working-directory: ./materialious steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: context: ./materialious + platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: wardpearce/materialious:latest diff --git a/materialious/src/app.d.ts b/materialious/src/app.d.ts index bffe90f7..743f07b2 100644 --- a/materialious/src/app.d.ts +++ b/materialious/src/app.d.ts @@ -10,5 +10,4 @@ declare global { } } -export { }; - +export {}; diff --git a/materialious/src/app.html b/materialious/src/app.html index ebd4066f..54bbb297 100644 --- a/materialious/src/app.html +++ b/materialious/src/app.html @@ -1,20 +1,21 @@ + + + + + + + + + Materialious + %sveltekit.head% + - - - - - - - - - Materialious - %sveltekit.head% - - - -
%sveltekit.body%
- - - \ No newline at end of file + +
%sveltekit.body%
+ + diff --git a/materialious/src/lib/Api/index.ts b/materialious/src/lib/Api/index.ts index de658c84..9d5afc97 100644 --- a/materialious/src/lib/Api/index.ts +++ b/materialious/src/lib/Api/index.ts @@ -1,239 +1,293 @@ import { get } from 'svelte/store'; -import { auth, deArrowInstance, deArrowThumbnailInstance, returnYTDislikesInstance } from '../../store'; -import type { Channel, ChannelContentPlaylists, ChannelContentVideos, ChannelPage, Comments, DeArrow, Playlist, PlaylistPage, ReturnYTDislikes, SearchSuggestion, Subscription, Video, VideoPlay } from './model'; +import { + auth, + deArrowInstance, + deArrowThumbnailInstance, + returnYTDislikesInstance +} from '../../store'; +import type { + Channel, + ChannelContentPlaylists, + ChannelContentVideos, + ChannelPage, + Comments, + DeArrow, + Playlist, + PlaylistPage, + ReturnYTDislikes, + SearchSuggestion, + Subscription, + Video, + VideoPlay +} from './model'; export function buildPath(path: string): string { - return `${import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE}/api/v1/${path}`; + return `${import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE}/api/v1/${path}`; } export async function fetchErrorHandle(response: Response): Promise { - if (!response.ok) { - let message = 'Internal error'; - try { - const json = await response.json(); - message = 'errorBacktrace' in json ? json.errorBacktrace : json.error; - } catch { } - throw Error(message); - } + if (!response.ok) { + let message = 'Internal error'; + try { + const json = await response.json(); + message = 'errorBacktrace' in json ? json.errorBacktrace : json.error; + } catch { } + throw Error(message); + } - return response; + return response; } export function buildAuthHeaders(): { headers: { Authorization: string; }; } { - return { headers: { Authorization: `Bearer ${get(auth)?.token}` } }; + return { headers: { Authorization: `Bearer ${get(auth)?.token}` } }; } export async function getTrending(): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath('trending'))); - return await resp.json(); + const resp = await fetchErrorHandle(await fetch(buildPath('trending'))); + return await resp.json(); } export async function getPopular(): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath('popular'))); - return await resp.json(); + const resp = await fetchErrorHandle(await fetch(buildPath('popular'))); + return await resp.json(); } export async function getVideo(videoId: string, local: boolean = false): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath(`videos/${videoId}?local=${local}`))); - return await resp.json(); + const resp = await fetchErrorHandle(await fetch(buildPath(`videos/${videoId}?local=${local}`))); + return await resp.json(); } export async function getDislikes(videoId: string): Promise { - const resp = await fetchErrorHandle(await fetch(`${get(returnYTDislikesInstance)}/votes?videoId=${videoId}`)); - return await resp.json(); + const resp = await fetchErrorHandle( + await fetch(`${get(returnYTDislikesInstance)}/votes?videoId=${videoId}`) + ); + return await resp.json(); } -export async function getComments(videoId: string, parameters: { - sort_by?: "top" | "new", - source?: "youtube" | "reddit", - continuation?: string; -}): Promise { - if (typeof parameters.sort_by === "undefined") { - parameters.sort_by = "top"; - } +export async function getComments( + videoId: string, + parameters: { + sort_by?: 'top' | 'new'; + source?: 'youtube' | 'reddit'; + continuation?: string; + } +): Promise { + if (typeof parameters.sort_by === 'undefined') { + parameters.sort_by = 'top'; + } - if (typeof parameters.source === "undefined") { - parameters.source = "youtube"; - } + if (typeof parameters.source === 'undefined') { + parameters.source = 'youtube'; + } - const path = new URL(buildPath(`comments/${videoId}`)); - path.search = new URLSearchParams(parameters).toString(); - const resp = await fetchErrorHandle(await fetch(path)); - return await resp.json(); + const path = new URL(buildPath(`comments/${videoId}`)); + path.search = new URLSearchParams(parameters).toString(); + const resp = await fetchErrorHandle(await fetch(path)); + return await resp.json(); } export async function getChannel(channelId: string): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath(`channels/${channelId}`))); - return await resp.json(); + const resp = await fetchErrorHandle(await fetch(buildPath(`channels/${channelId}`))); + return await resp.json(); } export async function getChannelContent( - channelId: string, - parameters: { - type?: 'videos' | 'playlists' | 'streams' | 'shorts'; - continuation?: string; - }): Promise { - if (typeof parameters.type === 'undefined') parameters.type = 'videos'; + channelId: string, + parameters: { + type?: 'videos' | 'playlists' | 'streams' | 'shorts'; + continuation?: string; + } +): Promise { + if (typeof parameters.type === 'undefined') parameters.type = 'videos'; - const url = new URL(buildPath(`channels/${channelId}/${parameters.type}`)); + const url = new URL(buildPath(`channels/${channelId}/${parameters.type}`)); - if (typeof parameters.continuation !== 'undefined') url.searchParams.set('continuation', parameters.continuation); + if (typeof parameters.continuation !== 'undefined') + url.searchParams.set('continuation', parameters.continuation); - const resp = await fetchErrorHandle(await fetch(url.toString())); - return await resp.json(); + const resp = await fetchErrorHandle(await fetch(url.toString())); + return await resp.json(); } export async function getSearchSuggestions(search: string): Promise { - const path = new URL(buildPath("search/suggestions")); - path.search = new URLSearchParams({ q: search }).toString(); - const resp = await fetchErrorHandle(await fetch(path)); - return await resp.json(); + const path = new URL(buildPath('search/suggestions')); + path.search = new URLSearchParams({ q: search }).toString(); + const resp = await fetchErrorHandle(await fetch(path)); + return await resp.json(); } -export async function getSearch(search: string, options: { - sort_by?: "relevance" | "rating" | "upload_date" | "view_count", - type?: "video" | "playlist" | "channel" | "all"; - page?: string; -}): Promise<(Channel | Video | Playlist)[]> { - if (typeof options.sort_by === "undefined") { - options.sort_by = "relevance"; - } +export async function getSearch( + search: string, + options: { + sort_by?: 'relevance' | 'rating' | 'upload_date' | 'view_count'; + type?: 'video' | 'playlist' | 'channel' | 'all'; + page?: string; + } +): Promise<(Channel | Video | Playlist)[]> { + if (typeof options.sort_by === 'undefined') { + options.sort_by = 'relevance'; + } - if (typeof options.type === "undefined") { - options.type = "video"; - } + if (typeof options.type === 'undefined') { + options.type = 'video'; + } - if (typeof options.page === "undefined") { - options.page = "1"; - } + if (typeof options.page === 'undefined') { + options.page = '1'; + } - const path = new URL(buildPath("search")); - path.search = new URLSearchParams({ ...options, q: search }).toString(); - const resp = await fetchErrorHandle(await fetch(path)); - return await resp.json(); + const path = new URL(buildPath('search')); + path.search = new URLSearchParams({ ...options, q: search }).toString(); + const resp = await fetchErrorHandle(await fetch(path)); + return await resp.json(); } export async function getFeed(maxResults: number, page: number) { - const path = new URL(buildPath("auth/feed")); - path.search = new URLSearchParams({ max_results: maxResults.toString(), page: page.toString() }).toString(); - const resp = await fetchErrorHandle(await fetch(path, buildAuthHeaders())); - return await resp.json(); + const path = new URL(buildPath('auth/feed')); + path.search = new URLSearchParams({ + max_results: maxResults.toString(), + page: page.toString() + }).toString(); + const resp = await fetchErrorHandle(await fetch(path, buildAuthHeaders())); + return await resp.json(); } export async function getSubscriptions(): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath("auth/subscriptions"), buildAuthHeaders())); - return await resp.json(); + const resp = await fetchErrorHandle( + await fetch(buildPath('auth/subscriptions'), buildAuthHeaders()) + ); + return await resp.json(); } export async function amSubscribed(authorId: string): Promise { - try { - const subscriptions = (await getSubscriptions()).filter(sub => sub.authorId === authorId); - return subscriptions.length === 1; - } catch { - return false; - } + try { + const subscriptions = (await getSubscriptions()).filter((sub) => sub.authorId === authorId); + return subscriptions.length === 1; + } catch { + return false; + } } export async function postSubscribe(authorId: string) { - await fetchErrorHandle(await fetch(buildPath(`auth/subscriptions/${authorId}`), { - method: "POST", - ...buildAuthHeaders() - })); + await fetchErrorHandle( + await fetch(buildPath(`auth/subscriptions/${authorId}`), { + method: 'POST', + ...buildAuthHeaders() + }) + ); } export async function deleteUnsubscribe(authorId: string) { - await fetchErrorHandle(await fetch(buildPath(`auth/subscriptions/${authorId}`), { - method: 'DELETE', - ...buildAuthHeaders() - })); + await fetchErrorHandle( + await fetch(buildPath(`auth/subscriptions/${authorId}`), { + method: 'DELETE', + ...buildAuthHeaders() + }) + ); } export async function getHistory(page: number = 1): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath(`auth/history?page=${page}`), buildAuthHeaders())); - return await resp.json(); + const resp = await fetchErrorHandle( + await fetch(buildPath(`auth/history?page=${page}`), buildAuthHeaders()) + ); + return await resp.json(); } export async function deleteHistory(videoId: string | undefined = undefined) { - let url = '/api/v1/auth/history'; - if (typeof videoId !== 'undefined') { - url += `/${videoId}`; - } + let url = '/api/v1/auth/history'; + if (typeof videoId !== 'undefined') { + url += `/${videoId}`; + } - await fetchErrorHandle(await fetch(buildPath(url), { - method: 'DELETE', - ...buildAuthHeaders() - })); + await fetchErrorHandle( + await fetch(buildPath(url), { + method: 'DELETE', + ...buildAuthHeaders() + }) + ); } export async function postHistory(videoId: string) { - await fetchErrorHandle(await fetch(buildPath(`auth/history/${videoId}`), { - method: 'POST', - ...buildAuthHeaders() - })); + await fetchErrorHandle( + await fetch(buildPath(`auth/history/${videoId}`), { + method: 'POST', + ...buildAuthHeaders() + }) + ); } export async function getPlaylist(playlistId: string, page: number = 1): Promise { - let resp; + let resp; - if (get(auth)) { - resp = await fetch(buildPath(`auth/playlists/${playlistId}?page=${page}`), buildAuthHeaders()); - } else { - resp = await fetch(buildPath(`playlists/${playlistId}?page=${page}`)); - } - await fetchErrorHandle(resp); - return await resp.json(); + if (get(auth)) { + resp = await fetch(buildPath(`auth/playlists/${playlistId}?page=${page}`), buildAuthHeaders()); + } else { + resp = await fetch(buildPath(`playlists/${playlistId}?page=${page}`)); + } + await fetchErrorHandle(resp); + return await resp.json(); } export async function getPersonalPlaylists(): Promise { - const resp = await fetchErrorHandle(await fetch(buildPath('auth/playlists'), buildAuthHeaders())); - return await resp.json(); + const resp = await fetchErrorHandle(await fetch(buildPath('auth/playlists'), buildAuthHeaders())); + return await resp.json(); } export async function deletePersonalPlaylist(playlistId: string) { - await fetchErrorHandle(await fetch(buildPath(`auth/playlists/${playlistId}`), { - method: 'DELETE', - ...buildAuthHeaders() - })); + await fetchErrorHandle( + await fetch(buildPath(`auth/playlists/${playlistId}`), { + method: 'DELETE', + ...buildAuthHeaders() + }) + ); } -export async function postPersonalPlaylist(title: string, privacy: 'public' | 'private' | 'unlisted') { - let headers: Record> = buildAuthHeaders(); - headers['headers']['Content-type'] = 'application/json'; +export async function postPersonalPlaylist( + title: string, + privacy: 'public' | 'private' | 'unlisted' +) { + const headers: Record> = buildAuthHeaders(); + headers['headers']['Content-type'] = 'application/json'; - await fetchErrorHandle(await fetch(buildPath('auth/playlists'), { - method: 'POST', - body: JSON.stringify({ - title: title, - privacy: privacy - }), - ...headers - })); + await fetchErrorHandle( + await fetch(buildPath('auth/playlists'), { + method: 'POST', + body: JSON.stringify({ + title: title, + privacy: privacy + }), + ...headers + }) + ); } export async function addPlaylistVideo(playlistId: string, videoId: string) { - let headers: Record> = buildAuthHeaders(); - headers['headers']['Content-type'] = 'application/json'; + const headers: Record> = buildAuthHeaders(); + headers['headers']['Content-type'] = 'application/json'; - await fetchErrorHandle(await fetch(buildPath(`auth/playlists/${playlistId}/videos`), { - method: 'POST', - body: JSON.stringify({ - videoId: videoId - }), - ...headers - })); + await fetchErrorHandle( + await fetch(buildPath(`auth/playlists/${playlistId}/videos`), { + method: 'POST', + body: JSON.stringify({ + videoId: videoId + }), + ...headers + }) + ); } export async function getDeArrow(videoId: string): Promise { - const resp = await fetchErrorHandle( - await fetch(`${get(deArrowInstance)}/api/branding?videoID=${videoId}` - ) - ); - return await resp.json(); + const resp = await fetchErrorHandle( + await fetch(`${get(deArrowInstance)}/api/branding?videoID=${videoId}`) + ); + return await resp.json(); } export async function getThumbnail(videoId: string, time: number): Promise { - const resp = await fetchErrorHandle( - await fetch(`${get(deArrowThumbnailInstance)}/api/v1/getThumbnail?videoID=${videoId}&time=${time}`) - ); - return URL.createObjectURL(await resp.blob()); -} \ No newline at end of file + const resp = await fetchErrorHandle( + await fetch( + `${get(deArrowThumbnailInstance)}/api/v1/getThumbnail?videoID=${videoId}&time=${time}` + ) + ); + return URL.createObjectURL(await resp.blob()); +} diff --git a/materialious/src/lib/Api/model.ts b/materialious/src/lib/Api/model.ts index dbb0e9c0..2046fc82 100644 --- a/materialious/src/lib/Api/model.ts +++ b/materialious/src/lib/Api/model.ts @@ -1,252 +1,251 @@ export interface Image { - url: string; - width: number; - height: number; + url: string; + width: number; + height: number; } export interface Thumbnail { - quality: string; - url: string; - width: number; - height: number; + quality: string; + url: string; + width: number; + height: number; } - export interface VideoBase { - videoId: string; - title: string; - videoThumbnails: Thumbnail[]; - author: string; - authorId: string; - lengthSeconds: number; - viewCountText: string; + videoId: string; + title: string; + videoThumbnails: Thumbnail[]; + author: string; + authorId: string; + lengthSeconds: number; + viewCountText: string; } export interface Video extends VideoBase { - type: "video"; - title: string; - authorUrl: string; - authorVerified: boolean; - description: string; - descriptionHtml: string; - viewCount: number; - published: number; - publishedText: string; - premiereTimestamp: number; - liveNow: boolean; - premium: boolean; - isUpcoming: boolean; + type: 'video'; + title: string; + authorUrl: string; + authorVerified: boolean; + description: string; + descriptionHtml: string; + viewCount: number; + published: number; + publishedText: string; + premiereTimestamp: number; + liveNow: boolean; + premium: boolean; + isUpcoming: boolean; } export interface AdaptiveFormats { - index: string; - bitrate: string; - init: string; - url: string; - itag: string; - type: string; - clen: string; - lmt: string; - projectionType: number; - container?: string; - encoding?: string; - qualityLabel?: string; - resolution?: string; - audioQuality?: string; + index: string; + bitrate: string; + init: string; + url: string; + itag: string; + type: string; + clen: string; + lmt: string; + projectionType: number; + container?: string; + encoding?: string; + qualityLabel?: string; + resolution?: string; + audioQuality?: string; } export interface FormatStreams { - url: string; - itag: string; - type: string; - quality: string; - container: string; - encoding: string; - qualityLabel: string; - resolution: string; - size: string; + url: string; + itag: string; + type: string; + quality: string; + container: string; + encoding: string; + qualityLabel: string; + resolution: string; + size: string; } export interface Captions { - label: string; - language_code: string; - url: string; -}; + label: string; + language_code: string; + url: string; +} export interface VideoPlay extends Video { - keywords: string[]; - likeCount: number; - dislikeCount: number; - subCountText: string; - allowRatings: boolean; - rating: number; - isListed: number; - isFamilyFriendly: boolean; - allowedRegions: string[]; - genre: string; - genreUrl: string; - hlsUrl?: string; - dashUrl: string; - adaptiveFormats: AdaptiveFormats[]; - formatStreams: FormatStreams[]; - recommendedVideos: VideoBase[]; - authorThumbnails: Image[]; - captions: Captions[]; - storyboards?: { - url: string; - templateUrl: string; - width: number; - height: number; - count: number; - interval: number; - storyboardWidth: number; - storyboardHeight: number; - storyboardCount: number; - }[]; + keywords: string[]; + likeCount: number; + dislikeCount: number; + subCountText: string; + allowRatings: boolean; + rating: number; + isListed: number; + isFamilyFriendly: boolean; + allowedRegions: string[]; + genre: string; + genreUrl: string; + hlsUrl?: string; + dashUrl: string; + adaptiveFormats: AdaptiveFormats[]; + formatStreams: FormatStreams[]; + recommendedVideos: VideoBase[]; + authorThumbnails: Image[]; + captions: Captions[]; + storyboards?: { + url: string; + templateUrl: string; + width: number; + height: number; + count: number; + interval: number; + storyboardWidth: number; + storyboardHeight: number; + storyboardCount: number; + }[]; } export interface ReturnYTDislikes { - id: string; - dateCreated: string; - likes: number; - dislikes: number; - rating: number; - viewCount: number; - deleted: boolean; + id: string; + dateCreated: string; + likes: number; + dislikes: number; + rating: number; + viewCount: number; + deleted: boolean; } export interface Comment { - author: string; - authorThumbnails: Image[]; - authorID: string; - authorUrl: string; - isEdited: boolean; - isPinned: boolean; - content: string; - contentHtml: string; - published: number; - publishedText: string; - likeCount: number; - authorIsChannelOwner: boolean; - creatorHeart: { - creatorThumbnail: string; - creatorName: string; - }; - replies: { - replyCount: number; - continuation: string; - }; + author: string; + authorThumbnails: Image[]; + authorID: string; + authorUrl: string; + isEdited: boolean; + isPinned: boolean; + content: string; + contentHtml: string; + published: number; + publishedText: string; + likeCount: number; + authorIsChannelOwner: boolean; + creatorHeart: { + creatorThumbnail: string; + creatorName: string; + }; + replies: { + replyCount: number; + continuation: string; + }; } export interface Comments { - commentCount: number; - videoId: string; - continuation?: string; - comments: Comment[]; + commentCount: number; + videoId: string; + continuation?: string; + comments: Comment[]; } export interface Channel { - type: "channel"; - author: string; - authorId: string; - authorUrl: string; - authorVerified: boolean; - subCount: number; - totalViews: number; - autoGenerated: boolean; - description: string; - descriptionHml: string; - authorThumbnails: Image[]; + type: 'channel'; + author: string; + authorId: string; + authorUrl: string; + authorVerified: boolean; + subCount: number; + totalViews: number; + autoGenerated: boolean; + description: string; + descriptionHml: string; + authorThumbnails: Image[]; } export interface PlaylistVideo { - title: string; - videoId: string; - lengthSeconds: number; - videoThumbnails: Thumbnail[]; + title: string; + videoId: string; + lengthSeconds: number; + videoThumbnails: Thumbnail[]; } export interface Playlist { - type: "playlist"; - title: string; - playlistId: string; - playlistThumbnail: string; - author: string; - authorId: string; - authorVerified: boolean; - videoCount: number; - videos: PlaylistVideo[]; + type: 'playlist'; + title: string; + playlistId: string; + playlistThumbnail: string; + author: string; + authorId: string; + authorVerified: boolean; + videoCount: number; + videos: PlaylistVideo[]; } export interface PlaylistPageVideo extends PlaylistVideo { - author: string; - index: number; - authorId: string; - viewCount: number; + author: string; + index: number; + authorId: string; + viewCount: number; } export interface ChannelContentVideos { - videos: Video[]; - continuation: string; + videos: Video[]; + continuation: string; } export interface ChannelContentPlaylists { - playlists: PlaylistPage[]; - continuation: string; + playlists: PlaylistPage[]; + continuation: string; } export interface PlaylistPage extends Playlist { - description: string; - descriptionHtml: string; - viewCount: number; - updated: number; - isListed: boolean; - videos: PlaylistPageVideo[]; + description: string; + descriptionHtml: string; + viewCount: number; + updated: number; + isListed: boolean; + videos: PlaylistPageVideo[]; } export interface ChannelPage extends Channel { - allowedRegions: string[]; - tabs: string[]; - latestVideos: Video[]; - isFamilyFriendly: boolean; - joined: number; - authorBanners: Image[]; + allowedRegions: string[]; + tabs: string[]; + latestVideos: Video[]; + isFamilyFriendly: boolean; + joined: number; + authorBanners: Image[]; } export interface SearchSuggestion { - query: string; - suggestions: string[]; + query: string; + suggestions: string[]; } export interface Notification extends VideoBase { - type: "video" | "shortVideo" | "stream"; + type: 'video' | 'shortVideo' | 'stream'; } export interface Feed { - notifications: Notification[]; - videos: Video[]; + notifications: Notification[]; + videos: Video[]; } export interface Subscription { - author: string; - authorId: string; + author: string; + authorId: string; } export interface DeArrow { - titles: { - title: string; - original: boolean; - votes: number; - locked: boolean; - UUID: string; - }[]; - thumbnails: { - timestamp: number | null; - original: boolean; - votes: number; - locked: boolean; - UUID: string; - }[]; - randomTime: number; - videoDuration: number; -} \ No newline at end of file + titles: { + title: string; + original: boolean; + votes: number; + locked: boolean; + UUID: string; + }[]; + thumbnails: { + timestamp: number | null; + original: boolean; + votes: number; + locked: boolean; + UUID: string; + }[]; + randomTime: number; + videoDuration: number; +} diff --git a/materialious/src/lib/ChannelThumbnail.svelte b/materialious/src/lib/ChannelThumbnail.svelte index 49aa667a..fdae55e7 100644 --- a/materialious/src/lib/ChannelThumbnail.svelte +++ b/materialious/src/lib/ChannelThumbnail.svelte @@ -7,8 +7,6 @@ export let channel: Channel; let loading = true; - let loaded = false; - let failed = false; let img: HTMLImageElement; @@ -17,12 +15,10 @@ img.src = channel.authorThumbnails[0].url; img.onload = () => { - loaded = true; loading = false; }; img.onerror = () => { loading = false; - failed = true; }; }); diff --git a/materialious/src/lib/bookmarklet.ts b/materialious/src/lib/bookmarklet.ts index da51299a..26ddb6f8 100644 --- a/materialious/src/lib/bookmarklet.ts +++ b/materialious/src/lib/bookmarklet.ts @@ -1,154 +1,154 @@ -import { page } from "$app/stores"; -import { get } from "svelte/store"; +import { page } from '$app/stores'; +import { get } from 'svelte/store'; import { - darkMode, - deArrowEnabled, - deArrowInstance, - deArrowThumbnailInstance, - interfaceSearchSuggestions, - playerAlwaysLoop, - playerAutoPlay, - playerAutoplayNextByDefault, - playerDash, - playerListenByDefault, - playerProxyVideos, - playerSavePlaybackPosition, - playerTheatreModeByDefault, - returnYTDislikesInstance, - sponsorBlock, - sponsorBlockCategories, - sponsorBlockUrl, - themeColor -} from "../store"; + darkMode, + deArrowEnabled, + deArrowInstance, + deArrowThumbnailInstance, + interfaceSearchSuggestions, + playerAlwaysLoop, + playerAutoPlay, + playerAutoplayNextByDefault, + playerDash, + playerListenByDefault, + playerProxyVideos, + playerSavePlaybackPosition, + playerTheatreModeByDefault, + returnYTDislikesInstance, + sponsorBlock, + sponsorBlockCategories, + sponsorBlockUrl, + themeColor +} from '../store'; const persistedStores = [ - { - name: 'returnYTDislikesInstance', - store: returnYTDislikesInstance, - type: 'string' - }, - { - name: 'darkMode', - store: darkMode, - type: 'boolean' - }, - { - name: 'themeColor', - store: themeColor, - type: 'string' - }, - { - name: 'autoPlay', - store: playerAutoPlay, - type: 'boolean' - }, - { - name: 'alwaysLoop', - store: playerAlwaysLoop, - type: 'boolean' - }, - { - name: 'proxyVideos', - store: playerProxyVideos, - type: 'boolean' - }, - { - name: 'listenByDefault', - store: playerListenByDefault, - type: 'boolean' - }, - { - name: 'savePlaybackPosition', - store: playerSavePlaybackPosition, - type: 'boolean' - }, - { - name: 'dashEnabled', - store: playerDash, - type: 'boolean' - }, - { - name: 'theatreModeByDefault', - store: playerTheatreModeByDefault, - type: 'boolean' - }, - { - name: 'autoplayNextByDefault', - store: playerAutoplayNextByDefault, - type: 'boolean' - }, - { - name: 'returnYtDislikes', - store: returnYTDislikesInstance, - type: 'boolean' - }, - { - name: 'searchSuggestions', - store: interfaceSearchSuggestions, - type: 'boolean' - }, - { - name: 'sponsorBlock', - store: sponsorBlock, - type: 'boolean' - }, - { - name: 'sponsorBlockUrl', - store: sponsorBlockUrl, - type: 'string' - }, - { - name: 'sponsorBlockCategories', - store: sponsorBlockCategories, - type: 'array' - }, - { - name: 'deArrowInstance', - store: deArrowInstance, - type: 'string' - }, - { - name: 'deArrowEnabled', - store: deArrowEnabled, - type: 'boolean' - }, - { - name: 'deArrowThumbnailInstance', - store: deArrowThumbnailInstance, - type: 'string' - } + { + name: 'returnYTDislikesInstance', + store: returnYTDislikesInstance, + type: 'string' + }, + { + name: 'darkMode', + store: darkMode, + type: 'boolean' + }, + { + name: 'themeColor', + store: themeColor, + type: 'string' + }, + { + name: 'autoPlay', + store: playerAutoPlay, + type: 'boolean' + }, + { + name: 'alwaysLoop', + store: playerAlwaysLoop, + type: 'boolean' + }, + { + name: 'proxyVideos', + store: playerProxyVideos, + type: 'boolean' + }, + { + name: 'listenByDefault', + store: playerListenByDefault, + type: 'boolean' + }, + { + name: 'savePlaybackPosition', + store: playerSavePlaybackPosition, + type: 'boolean' + }, + { + name: 'dashEnabled', + store: playerDash, + type: 'boolean' + }, + { + name: 'theatreModeByDefault', + store: playerTheatreModeByDefault, + type: 'boolean' + }, + { + name: 'autoplayNextByDefault', + store: playerAutoplayNextByDefault, + type: 'boolean' + }, + { + name: 'returnYtDislikes', + store: returnYTDislikesInstance, + type: 'boolean' + }, + { + name: 'searchSuggestions', + store: interfaceSearchSuggestions, + type: 'boolean' + }, + { + name: 'sponsorBlock', + store: sponsorBlock, + type: 'boolean' + }, + { + name: 'sponsorBlockUrl', + store: sponsorBlockUrl, + type: 'string' + }, + { + name: 'sponsorBlockCategories', + store: sponsorBlockCategories, + type: 'array' + }, + { + name: 'deArrowInstance', + store: deArrowInstance, + type: 'string' + }, + { + name: 'deArrowEnabled', + store: deArrowEnabled, + type: 'boolean' + }, + { + name: 'deArrowThumbnailInstance', + store: deArrowThumbnailInstance, + type: 'string' + } ]; export function bookmarkletSaveToUrl(): string { - const url = new URL(import.meta.env.VITE_DEFAULT_FRONTEND_URL); + const url = new URL(import.meta.env.VITE_DEFAULT_FRONTEND_URL); - persistedStores.forEach(store => { - let value = get(store.store); - if (value !== null) { - url.searchParams.set(store.name, value.toString()); - } - }); + persistedStores.forEach((store) => { + let value = get(store.store); + if (value !== null) { + url.searchParams.set(store.name, value.toString()); + } + }); - return url.toString(); + return url.toString(); } export function bookmarkletLoadFromUrl() { - const currentPage = get(page); + const currentPage = get(page); - persistedStores.forEach(store => { - let paramValue = currentPage.url.searchParams.get(store.name); - if (paramValue) { - let value: any; + persistedStores.forEach((store) => { + let paramValue = currentPage.url.searchParams.get(store.name); + if (paramValue) { + let value: any; - if (store.type === 'array') { - value = paramValue.split(','); - } else if (store.type === 'boolean') { - value = paramValue === 'true'; - } else { - value = paramValue; - } + if (store.type === 'array') { + value = paramValue.split(','); + } else if (store.type === 'boolean') { + value = paramValue === 'true'; + } else { + value = paramValue; + } - store.store.set(value); - } - }); -} \ No newline at end of file + store.store.set(value); + } + }); +} diff --git a/materialious/src/lib/i18n/index.ts b/materialious/src/lib/i18n/index.ts index e5e2ca7c..a4662813 100644 --- a/materialious/src/lib/i18n/index.ts +++ b/materialious/src/lib/i18n/index.ts @@ -6,6 +6,6 @@ const defaultLocale = 'en'; register('en', () => import('./locales/en.json')); init({ - fallbackLocale: defaultLocale, - initialLocale: browser ? window.navigator.language : defaultLocale, + fallbackLocale: defaultLocale, + initialLocale: browser ? window.navigator.language : defaultLocale }); diff --git a/materialious/src/lib/i18n/locales/en.json b/materialious/src/lib/i18n/locales/en.json index 3030d26a..1581e067 100644 --- a/materialious/src/lib/i18n/locales/en.json +++ b/materialious/src/lib/i18n/locales/en.json @@ -1,110 +1,110 @@ { - "enabled": "Enabled", - "copyUrl": "Copy URL", - "loadMore": "Load more", - "views": "views", - "videos": "videos", - "cancel": "Cancel", - "create": "Create", - "title": "Title", - "searchPlaceholder": "Search...", - "deleteAllHistory": "Delete all history", - "skipping": "Skipping", - "replies": "replies", - "videoTabs": { - "all": "All", - "videos": "Videos", - "playlists": "Playlists", - "channels": "Channels", - "shorts": "Shorts", - "streams": "Streams" - }, - "subscriptions": { - "manageSubscriptions": "Manage subscriptions" - }, - "playlist": { - "createPlaylist": "Create playlist", - "public": "Public", - "unlisted": "Unlisted", - "private": "Private" - }, - "thumbnail": { - "live": "LIVE", - "failedToLoadImage": "Failed to load image" - }, - "pages": { - "home": "Home", - "trending": "Trending", - "subscriptions": "Subscriptions", - "playlists": "Playlists", - "history": "History" - }, - "subscribers": "subscribers", - "subscribe": "Subscribe", - "unsubscribe": "Unsubscribe", - "loginRequired": "Login required", - "player": { - "audioOnly": "Audio only", - "theatreMode": "Theatre mode", - "share": { - "title": "Share", - "materialiousLink": "Copy Materialious link", - "invidiousRedirect": "Copy Invidious redirect link", - "youtubeLink": "Copy Youtube link" - }, - "download": "Download", - "addToPlaylist": "Add to playlist", - "noPlaylists": "No playlists", - "unableToLoadComments": "Unable to load comments" - }, - "layout": { - "star": "Star us on Github!", - "syncParty": "Sync party", - "syncPartyWarning": "Please note your IP will be visible to users you invite.", - "startSyncParty": "Start sync party", - "endSyncParty": "End sync party", - "notifications": "Notifications", - "noNewNotifications": "No new notifications here", - "settings": "Settings", - "login": "Login", - "logout": "Logout", - "customize": "Customize", - "theme": { - "theme": "Theme", - "darkMode": "Dark mode", - "lightMode": "Light mode", - "color": "Color" - }, - "searchSuggestions": "Search suggestions", - "dataPreferences": { - "dataPreferences": "Data preferences", - "content": "Looking to import/export subscriptions, change password or delete account? Click here and scroll to the bottom of the page." - }, - "player": { - "title": "Player", - "autoPlay": "Autoplay video", - "alwaysLoopVideo": "Always loop video", - "proxyVideos": "Proxy videos", - "savePlaybackPosition": "Save playback position", - "listenByDefault": "Listen by default", - "theatreModeByDefault": "Theatre mode by default", - "autoPlayNextByDefault": "Autoplay next by default", - "dash": "Dash" - }, - "instanceUrl": "Instance URL", - "sponsors": { - "sponsor": "Sponsor", - "unpaidSelfPromotion": "Unpaid/Self Promotion", - "interactionReminder": "Interaction Reminder (Subscribe)", - "intermissionIntroAnimation": "Intermission/Intro Animation", - "credits": "Endcards/Credits", - "preViewRecapHook": "Preview/Recap/Hook", - "tangentJokes": "Filler Tangent/Jokes" - }, - "deArrow": { - "title": "DeArrow", - "thumbnailInstanceUrl": "Thumbnail instance URL" - }, - "bookmarklet": "Bookmarklet" - } -} \ No newline at end of file + "enabled": "Enabled", + "copyUrl": "Copy URL", + "loadMore": "Load more", + "views": "views", + "videos": "videos", + "cancel": "Cancel", + "create": "Create", + "title": "Title", + "searchPlaceholder": "Search...", + "deleteAllHistory": "Delete all history", + "skipping": "Skipping", + "replies": "replies", + "videoTabs": { + "all": "All", + "videos": "Videos", + "playlists": "Playlists", + "channels": "Channels", + "shorts": "Shorts", + "streams": "Streams" + }, + "subscriptions": { + "manageSubscriptions": "Manage subscriptions" + }, + "playlist": { + "createPlaylist": "Create playlist", + "public": "Public", + "unlisted": "Unlisted", + "private": "Private" + }, + "thumbnail": { + "live": "LIVE", + "failedToLoadImage": "Failed to load image" + }, + "pages": { + "home": "Home", + "trending": "Trending", + "subscriptions": "Subscriptions", + "playlists": "Playlists", + "history": "History" + }, + "subscribers": "subscribers", + "subscribe": "Subscribe", + "unsubscribe": "Unsubscribe", + "loginRequired": "Login required", + "player": { + "audioOnly": "Audio only", + "theatreMode": "Theatre mode", + "share": { + "title": "Share", + "materialiousLink": "Copy Materialious link", + "invidiousRedirect": "Copy Invidious redirect link", + "youtubeLink": "Copy Youtube link" + }, + "download": "Download", + "addToPlaylist": "Add to playlist", + "noPlaylists": "No playlists", + "unableToLoadComments": "Unable to load comments" + }, + "layout": { + "star": "Star us on Github!", + "syncParty": "Sync party", + "syncPartyWarning": "Please note your IP will be visible to users you invite.", + "startSyncParty": "Start sync party", + "endSyncParty": "End sync party", + "notifications": "Notifications", + "noNewNotifications": "No new notifications here", + "settings": "Settings", + "login": "Login", + "logout": "Logout", + "customize": "Customize", + "theme": { + "theme": "Theme", + "darkMode": "Dark mode", + "lightMode": "Light mode", + "color": "Color" + }, + "searchSuggestions": "Search suggestions", + "dataPreferences": { + "dataPreferences": "Data preferences", + "content": "Looking to import/export subscriptions, change password or delete account? Click here and scroll to the bottom of the page." + }, + "player": { + "title": "Player", + "autoPlay": "Autoplay video", + "alwaysLoopVideo": "Always loop video", + "proxyVideos": "Proxy videos", + "savePlaybackPosition": "Save playback position", + "listenByDefault": "Listen by default", + "theatreModeByDefault": "Theatre mode by default", + "autoPlayNextByDefault": "Autoplay next by default", + "dash": "Dash" + }, + "instanceUrl": "Instance URL", + "sponsors": { + "sponsor": "Sponsor", + "unpaidSelfPromotion": "Unpaid/Self Promotion", + "interactionReminder": "Interaction Reminder (Subscribe)", + "intermissionIntroAnimation": "Intermission/Intro Animation", + "credits": "Endcards/Credits", + "preViewRecapHook": "Preview/Recap/Hook", + "tangentJokes": "Filler Tangent/Jokes" + }, + "deArrow": { + "title": "DeArrow", + "thumbnailInstanceUrl": "Thumbnail instance URL" + }, + "bookmarklet": "Bookmarklet" + } +} diff --git a/materialious/src/lib/misc.ts b/materialious/src/lib/misc.ts index 1e49424f..64e4122a 100644 --- a/materialious/src/lib/misc.ts +++ b/materialious/src/lib/misc.ts @@ -1,104 +1,107 @@ -import humanNumber from "human-number"; +import humanNumber from 'human-number'; export function truncate(value: string, maxLength: number = 50): string { - return value.length > maxLength ? `${value.substring(0, maxLength)}...` : value; + return value.length > maxLength ? `${value.substring(0, maxLength)}...` : value; } export function numberWithCommas(number: number) { - if (typeof number === "undefined") return; - return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + if (typeof number === 'undefined') return; + 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)).replace('.0', ''); + return humanNumber(number, (number: number) => + Number.parseFloat(number.toString()).toFixed(1) + ).replace('.0', ''); } export function videoLength(lengthSeconds: number): string { - const hours = Math.floor(lengthSeconds / 3600); - let minutes: number | string = Math.floor((lengthSeconds % 3600) / 60); - let seconds: number | string = lengthSeconds % 60; + const hours = Math.floor(lengthSeconds / 3600); + let minutes: number | string = Math.floor((lengthSeconds % 3600) / 60); + let seconds: number | string = lengthSeconds % 60; - if (minutes < 10) { - minutes = `0${minutes}`; - } + if (minutes < 10) { + minutes = `0${minutes}`; + } - if (seconds < 10) { - seconds = `0${seconds}`; - } + if (seconds < 10) { + seconds = `0${seconds}`; + } - - if (hours !== 0) { - return `${hours}:${minutes}:${seconds}`; - } else { - return `${minutes}:${seconds}`; - } + if (hours !== 0) { + return `${hours}:${minutes}:${seconds}`; + } else { + return `${minutes}:${seconds}`; + } } export interface PhasedDescription { - description: string, timestamps: { title: string; time: number; timePretty: string; }[]; + description: string; + timestamps: { title: string; time: number; timePretty: string }[]; } export function phaseDescription(content: string): PhasedDescription { - const timestamps: { title: string; time: number; timePretty: string; }[] = []; - const lines = content.split('\n'); + const timestamps: { title: string; time: number; timePretty: string }[] = []; + const lines = content.split('\n'); - const urlRegex = /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; + const urlRegex = /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; - let filteredLines: string[] = []; - lines.forEach( - (line) => { - const urlMatch = urlRegex.exec(line); - const timestampMatch = timestampRegex.exec(line); + let filteredLines: string[] = []; + lines.forEach((line) => { + const urlMatch = urlRegex.exec(line); + const timestampMatch = timestampRegex.exec(line); - if (urlMatch !== null && timestampMatch === null) { - // If line contains a URL but not a timestamp, modify the URL - const modifiedLine = line.replace(/ parseInt(part)); - let seconds = 0; - if (parts.length === 3) { - // hh:mm:ss - seconds = parts[0] * 3600 + parts[1] * 60 + parts[2]; - } else if (parts.length === 2) { - // hh:ss or m:ss - seconds = parts[0] * 60 + parts[1]; - } else if (parts.length === 1) { - // s - seconds = parts[0]; - } - return seconds; + const parts = time.split(':').map((part) => parseInt(part)); + let seconds = 0; + if (parts.length === 3) { + // hh:mm:ss + seconds = parts[0] * 3600 + parts[1] * 60 + parts[2]; + } else if (parts.length === 2) { + // hh:ss or m:ss + seconds = parts[0] * 60 + parts[1]; + } else if (parts.length === 1) { + // s + seconds = parts[0]; + } + return seconds; } export function proxyVideoUrl(source: string): string { - const rawSrc = new URL(source); - rawSrc.host = import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE.replace( - 'http://', - '' - ).replace('https://', ''); + const rawSrc = new URL(source); + rawSrc.host = import.meta.env.VITE_DEFAULT_INVIDIOUS_INSTANCE.replace('http://', '').replace( + 'https://', + '' + ); - return rawSrc.toString(); -} \ No newline at end of file + return rawSrc.toString(); +} diff --git a/materialious/src/lib/player.ts b/materialious/src/lib/player.ts index 6da09ba7..a7fed004 100644 --- a/materialious/src/lib/player.ts +++ b/materialious/src/lib/player.ts @@ -1,10 +1,10 @@ export interface PlayerEvent { - type: "pause" | "seek" | "change-video" | "play" | "playlist"; - time?: number; - videoId?: string; - playlistId?: string; + type: 'pause' | 'seek' | 'change-video' | 'play' | 'playlist'; + time?: number; + videoId?: string; + playlistId?: string; } export interface PlayerEvents { - events: PlayerEvent[]; -} \ No newline at end of file + events: PlayerEvent[]; +} diff --git a/materialious/src/lib/theme.ts b/materialious/src/lib/theme.ts index 2ba537ee..ab6c14b8 100644 --- a/materialious/src/lib/theme.ts +++ b/materialious/src/lib/theme.ts @@ -1,12 +1,12 @@ export async function getDynamicTheme(mode?: string): Promise> { - const givenSettings = await window.ui("theme") as IBeerCssTheme; + const givenSettings = (await window.ui('theme')) as IBeerCssTheme; - // @ts-ignore - const themes: string = givenSettings[mode ? mode : (ui("mode") as string)]; - let themeVars: Record = {}; - themes.split(";").forEach(keyVar => { - let [key, value] = keyVar.split(":"); - themeVars[key] = value; - }); - return themeVars; -} \ No newline at end of file + // @ts-ignore + const themes: string = givenSettings[mode ? mode : (ui('mode') as string)]; + let themeVars: Record = {}; + themes.split(';').forEach((keyVar) => { + let [key, value] = keyVar.split(':'); + themeVars[key] = value; + }); + return themeVars; +} diff --git a/materialious/src/routes/+layout.ts b/materialious/src/routes/+layout.ts index 25c3ea60..d7f14dac 100644 --- a/materialious/src/routes/+layout.ts +++ b/materialious/src/routes/+layout.ts @@ -6,8 +6,8 @@ import type { LayoutLoad } from './$types'; export let ssr = false; export const load: LayoutLoad = async () => { - if (browser) { - locale.set(window.navigator.language); - } - await waitLocale(); -}; \ No newline at end of file + if (browser) { + locale.set(window.navigator.language); + } + await waitLocale(); +}; diff --git a/materialious/src/routes/+page.ts b/materialious/src/routes/+page.ts index faea9e87..21c1d06e 100644 --- a/materialious/src/routes/+page.ts +++ b/materialious/src/routes/+page.ts @@ -2,20 +2,20 @@ import { getPopular } from '$lib/Api/index.js'; import { error } from '@sveltejs/kit'; export async function load() { - let popular = undefined; - let popularDisabled: boolean = false; + let popular = undefined; + let popularDisabled: boolean = false; - try { - popular = await getPopular(); - } catch (errorMessage: any) { - if (errorMessage.toString() === 'Error: Administrator has disabled this endpoint.') { - popularDisabled = true; - } else { - error(500, errorMessage); - } - } - return { - popular: popular, - popularDisabled: popularDisabled - }; -} \ No newline at end of file + try { + popular = await getPopular(); + } catch (errorMessage: any) { + if (errorMessage.toString() === 'Error: Administrator has disabled this endpoint.') { + popularDisabled = true; + } else { + error(500, errorMessage); + } + } + return { + popular: popular, + popularDisabled: popularDisabled + }; +} diff --git a/materialious/src/routes/channel/[slug]/+page.ts b/materialious/src/routes/channel/[slug]/+page.ts index 276a818e..adb34605 100644 --- a/materialious/src/routes/channel/[slug]/+page.ts +++ b/materialious/src/routes/channel/[slug]/+page.ts @@ -2,15 +2,15 @@ import { getChannel } from '$lib/Api/index.js'; import { error } from '@sveltejs/kit'; export async function load({ params }) { - let channel; + let channel; - try { - channel = await getChannel(params.slug); - } catch (errorMessage: any) { - error(500, errorMessage); - } + try { + channel = await getChannel(params.slug); + } catch (errorMessage: any) { + error(500, errorMessage); + } - return { - channel: channel - }; -} \ No newline at end of file + return { + channel: channel + }; +} diff --git a/materialious/src/routes/playlist/+page.ts b/materialious/src/routes/playlist/+page.ts index f7c0637b..40b7e108 100644 --- a/materialious/src/routes/playlist/+page.ts +++ b/materialious/src/routes/playlist/+page.ts @@ -2,10 +2,10 @@ import { goto } from '$app/navigation'; import { error } from '@sveltejs/kit'; export async function load({ url }) { - const playlistId = url.searchParams.get('list'); - if (playlistId) { - goto(`/playlist/${playlistId}`); - } else { - error(404); - } -} \ No newline at end of file + const playlistId = url.searchParams.get('list'); + if (playlistId) { + goto(`/playlist/${playlistId}`); + } else { + error(404); + } +} diff --git a/materialious/src/routes/playlist/[slug]/+page.ts b/materialious/src/routes/playlist/[slug]/+page.ts index 939fe023..5b90c084 100644 --- a/materialious/src/routes/playlist/[slug]/+page.ts +++ b/materialious/src/routes/playlist/[slug]/+page.ts @@ -2,14 +2,14 @@ import { getPlaylist } from '$lib/Api/index.js'; import { error } from '@sveltejs/kit'; export async function load({ params }) { - let playlist; + let playlist; - try { - playlist = await getPlaylist(params.slug); - } catch (errorMessage: any) { - error(500, errorMessage); - } - return { - playlist: playlist - }; -} \ No newline at end of file + try { + playlist = await getPlaylist(params.slug); + } catch (errorMessage: any) { + error(500, errorMessage); + } + return { + playlist: playlist + }; +} diff --git a/materialious/src/routes/playlists/+page.ts b/materialious/src/routes/playlists/+page.ts index 2efe5cc1..b25032cd 100644 --- a/materialious/src/routes/playlists/+page.ts +++ b/materialious/src/routes/playlists/+page.ts @@ -1,14 +1,14 @@ -import { getPersonalPlaylists } from "$lib/Api"; -import { error } from "@sveltejs/kit"; +import { getPersonalPlaylists } from '$lib/Api'; +import { error } from '@sveltejs/kit'; export async function load() { - let playlists; - try { - playlists = await getPersonalPlaylists(); - } catch (errorMessage: any) { - error(500, errorMessage); - } - return { - playlists: playlists - }; -} \ No newline at end of file + let playlists; + try { + playlists = await getPersonalPlaylists(); + } catch (errorMessage: any) { + error(500, errorMessage); + } + return { + playlists: playlists + }; +} diff --git a/materialious/src/routes/search/[slug]/+page.ts b/materialious/src/routes/search/[slug]/+page.ts index 1b96ce67..3eb86f03 100644 --- a/materialious/src/routes/search/[slug]/+page.ts +++ b/materialious/src/routes/search/[slug]/+page.ts @@ -2,26 +2,26 @@ import { getSearch } from '$lib/Api/index'; import { error } from '@sveltejs/kit'; export async function load({ params, url }) { - let type: "playlist" | "all" | "video" | "channel"; + let type: 'playlist' | 'all' | 'video' | 'channel'; - const queryFlag = url.searchParams.get('type'); - if (queryFlag && ['playlist', 'video', 'channel', 'all'].includes(queryFlag)) { - type = queryFlag; - } else { - type = 'all'; - } + const queryFlag = url.searchParams.get('type'); + if (queryFlag && ['playlist', 'video', 'channel', 'all'].includes(queryFlag)) { + type = queryFlag; + } else { + type = 'all'; + } - let search; + let search; - try { - search = await getSearch(params.slug, { type: type }); - } catch (errorMessage: any) { - error(500, errorMessage); - } + try { + search = await getSearch(params.slug, { type: type }); + } catch (errorMessage: any) { + error(500, errorMessage); + } - return { - search: search, - slug: params.slug, - searchType: type - }; + return { + search: search, + slug: params.slug, + searchType: type + }; } diff --git a/materialious/src/routes/subscriptions/+page.ts b/materialious/src/routes/subscriptions/+page.ts index 1102ee7b..fc77bcda 100644 --- a/materialious/src/routes/subscriptions/+page.ts +++ b/materialious/src/routes/subscriptions/+page.ts @@ -2,14 +2,14 @@ import { getFeed } from '$lib/Api/index.js'; import { error } from '@sveltejs/kit'; export async function load({ params }) { - let feed; + let feed; - try { - feed = await getFeed(100, 1); - } catch (errorMessage: any) { - error(500, errorMessage); - } - return { - feed: feed - }; -} \ No newline at end of file + try { + feed = await getFeed(100, 1); + } catch (errorMessage: any) { + error(500, errorMessage); + } + return { + feed: feed + }; +} diff --git a/materialious/src/routes/subscriptions/manage/+page.ts b/materialious/src/routes/subscriptions/manage/+page.ts index 20322ba2..0686c8a2 100644 --- a/materialious/src/routes/subscriptions/manage/+page.ts +++ b/materialious/src/routes/subscriptions/manage/+page.ts @@ -1,16 +1,16 @@ -import { getSubscriptions } from "$lib/Api"; -import { error } from "@sveltejs/kit"; +import { getSubscriptions } from '$lib/Api'; +import { error } from '@sveltejs/kit'; export async function load() { - let subscriptions; + let subscriptions; - try { - subscriptions = await getSubscriptions(); - } catch (errorMessage: any) { - error(500, errorMessage); - } + try { + subscriptions = await getSubscriptions(); + } catch (errorMessage: any) { + error(500, errorMessage); + } - return { - subscriptions: subscriptions - }; -} \ No newline at end of file + return { + subscriptions: subscriptions + }; +} diff --git a/materialious/src/routes/trending/+page.ts b/materialious/src/routes/trending/+page.ts index a75195f2..0bb3ca46 100644 --- a/materialious/src/routes/trending/+page.ts +++ b/materialious/src/routes/trending/+page.ts @@ -3,12 +3,12 @@ import type { Video } from '$lib/Api/model'; import { error } from '@sveltejs/kit'; export async function load() { - let trending: Video[]; - try { - trending = await getTrending(); - } catch (errorMessage: any) { - error(500, errorMessage); - } + let trending: Video[]; + try { + trending = await getTrending(); + } catch (errorMessage: any) { + error(500, errorMessage); + } - return { trending: trending }; -} \ No newline at end of file + return { trending: trending }; +} diff --git a/materialious/src/routes/watch/+page.ts b/materialious/src/routes/watch/+page.ts index da580155..ea46d799 100644 --- a/materialious/src/routes/watch/+page.ts +++ b/materialious/src/routes/watch/+page.ts @@ -2,16 +2,16 @@ import { goto } from '$app/navigation'; import { error } from '@sveltejs/kit'; export async function load({ url }) { - const videoId = url.searchParams.get('v'); - const playlistId = url.searchParams.get('list'); - if (videoId) { - let goToUrl = `/watch/${videoId}`; + const videoId = url.searchParams.get('v'); + const playlistId = url.searchParams.get('list'); + if (videoId) { + let goToUrl = `/watch/${videoId}`; - if (playlistId) { - goToUrl += `?playlist=${playlistId}`; - } - goto(goToUrl); - } else { - error(404); - } -} \ No newline at end of file + if (playlistId) { + goToUrl += `?playlist=${playlistId}`; + } + goto(goToUrl); + } else { + error(404); + } +} diff --git a/materialious/src/routes/watch/[slug]/+page.ts b/materialious/src/routes/watch/[slug]/+page.ts index fdae0f04..bfb2d532 100644 --- a/materialious/src/routes/watch/[slug]/+page.ts +++ b/materialious/src/routes/watch/[slug]/+page.ts @@ -1,4 +1,11 @@ -import { amSubscribed, getComments, getDislikes, getPersonalPlaylists, getVideo, postHistory } from '$lib/Api/index.js'; +import { + amSubscribed, + getComments, + getDislikes, + getPersonalPlaylists, + getVideo, + postHistory +} from '$lib/Api/index.js'; import type { PlaylistPage } from '$lib/Api/model'; import { phaseDescription } from '$lib/misc'; import { error } from '@sveltejs/kit'; @@ -6,66 +13,68 @@ import { get } from 'svelte/store'; import { auth, playerProxyVideos, returnYtDislikes } from '../../../store'; export async function load({ params, url }) { - let video; - try { - video = await getVideo(params.slug, get(playerProxyVideos)); - } catch (errorMessage: any) { - error(500, errorMessage); - } + let video; + try { + video = await getVideo(params.slug, get(playerProxyVideos)); + } catch (errorMessage: any) { + error(500, errorMessage); + } - let downloadOptions: { title: string; url: string; }[] = []; + let downloadOptions: { title: string; url: string }[] = []; - if (!video.hlsUrl) { - video.formatStreams.forEach(format => { - downloadOptions.push({ - title: `${format.type.split(';')[0].trim()} - ${format.qualityLabel} (With audio)`, - url: format.url - }); - }); + if (!video.hlsUrl) { + video.formatStreams.forEach((format) => { + downloadOptions.push({ + title: `${format.type.split(';')[0].trim()} - ${format.qualityLabel} (With audio)`, + url: format.url + }); + }); - video.adaptiveFormats.forEach(format => { - downloadOptions.push({ - title: `${format.type.split(';')[0].trim()} - ${format.qualityLabel || format.bitrate + ' bitrate'}`, - url: format.url - }); - }); - } + video.adaptiveFormats.forEach((format) => { + downloadOptions.push({ + title: `${format.type.split(';')[0].trim()} - ${format.qualityLabel || format.bitrate + ' bitrate'}`, + url: format.url + }); + }); + } - let personalPlaylists: PlaylistPage[] | null; + let personalPlaylists: PlaylistPage[] | null; - if (get(auth)) { - postHistory(video.videoId); - personalPlaylists = await getPersonalPlaylists(); - } else { - personalPlaylists = null; - } + if (get(auth)) { + postHistory(video.videoId); + personalPlaylists = await getPersonalPlaylists(); + } else { + personalPlaylists = null; + } - let comments; - try { - comments = video.liveNow ? null : await getComments(params.slug, { sort_by: "top", source: "youtube" }); - } catch { - comments = null; - } + let comments; + try { + comments = video.liveNow + ? null + : await getComments(params.slug, { sort_by: 'top', source: 'youtube' }); + } catch { + comments = null; + } - if (comments && 'errorBacktrace' in comments) { - comments = null; - } + if (comments && 'errorBacktrace' in comments) { + comments = null; + } - let returnYTDislikes; - try { - returnYTDislikes = get(returnYtDislikes) ? await getDislikes(params.slug) : null; - } catch { - returnYTDislikes = null; - } + let returnYTDislikes; + try { + returnYTDislikes = get(returnYtDislikes) ? await getDislikes(params.slug) : null; + } catch { + returnYTDislikes = null; + } - return { - video: video, - returnYTDislikes: returnYTDislikes, - comments: comments, - subscribed: await amSubscribed(video.authorId), - content: phaseDescription(video.descriptionHtml), - playlistId: url.searchParams.get('playlist'), - personalPlaylists: personalPlaylists, - downloadOptions: downloadOptions - }; -}; + return { + video: video, + returnYTDislikes: returnYTDislikes, + comments: comments, + subscribed: await amSubscribed(video.authorId), + content: phaseDescription(video.descriptionHtml), + playlistId: url.searchParams.get('playlist'), + personalPlaylists: personalPlaylists, + downloadOptions: downloadOptions + }; +} diff --git a/materialious/src/store.ts b/materialious/src/store.ts index 595c2023..0e7fd1e5 100644 --- a/materialious/src/store.ts +++ b/materialious/src/store.ts @@ -3,34 +3,49 @@ import type { DataConnection } from 'peerjs'; import { persisted } from 'svelte-persisted-store'; import { writable, type Writable } from 'svelte/store'; -export const returnYTDislikesInstance = persisted('returnYTDislikesInstance', import.meta.env.VITE_DEFAULT_RETURNYTDISLIKES_INSTANCE); -export const darkMode: Writable = persisted("darkMode", null); -export const themeColor: Writable = persisted("themeColor", null); +export const returnYTDislikesInstance = persisted( + 'returnYTDislikesInstance', + import.meta.env.VITE_DEFAULT_RETURNYTDISLIKES_INSTANCE +); +export const darkMode: Writable = persisted('darkMode', null); +export const themeColor: Writable = persisted('themeColor', null); -export const activePage: Writable = writable("home"); +export const activePage: Writable = writable('home'); -export const playerAutoPlay = persisted("autoPlay", true); -export const playerAlwaysLoop = persisted("alwaysLoop", false); -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 playerAutoPlay = persisted('autoPlay', true); +export const playerAlwaysLoop = persisted('alwaysLoop', false); +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); +export const returnYtDislikes = persisted('returnYtDislikes', true); -export const interfaceSearchSuggestions = persisted("searchSuggestions", true); +export const interfaceSearchSuggestions = persisted('searchSuggestions', true); -export const auth: Writable = persisted("authToken", null); +export const auth: Writable = persisted( + 'authToken', + null +); -export const sponsorBlock = persisted("sponsorBlock", true); -export const sponsorBlockUrl = persisted("sponsorBlockUrl", import.meta.env.VITE_DEFAULT_SPONSERBLOCK_INSTANCE); -export const sponsorBlockCategories: Writable = persisted("sponsorBlockCategories", []); +export const sponsorBlock = persisted('sponsorBlock', true); +export const sponsorBlockUrl = persisted( + 'sponsorBlockUrl', + import.meta.env.VITE_DEFAULT_SPONSERBLOCK_INSTANCE +); +export const sponsorBlockCategories: Writable = persisted('sponsorBlockCategories', []); -export const deArrowInstance = persisted("deArrowInstance", import.meta.env.VITE_DEFAULT_DEARROW_INSTANCE); -export const deArrowEnabled = persisted("deArrowEnabled", false); -export const deArrowThumbnailInstance = persisted("deArrowThumbnailInstance", import.meta.env.VITE_DEFAULT_DEARROW_THUMBNAIL_INSTANCE); +export const deArrowInstance = persisted( + 'deArrowInstance', + import.meta.env.VITE_DEFAULT_DEARROW_INSTANCE +); +export const deArrowEnabled = persisted('deArrowEnabled', false); +export const deArrowThumbnailInstance = persisted( + 'deArrowThumbnailInstance', + import.meta.env.VITE_DEFAULT_DEARROW_THUMBNAIL_INSTANCE +); export const syncPartyPeer: Writable = writable(null); -export const syncPartyConnections: Writable = writable(); \ No newline at end of file +export const syncPartyConnections: Writable = writable(); diff --git a/materialious/static/style.css b/materialious/static/style.css index 9cd400b1..ecb8876c 100644 --- a/materialious/static/style.css +++ b/materialious/static/style.css @@ -1,29 +1,29 @@ .thumbnail-corner { - padding: .1em .4em; + padding: 0.1em 0.4em; } .vds-chapter-radio-label { - word-wrap: break-word !important; - overflow-wrap: break-word !important; - white-space: normal !important; + word-wrap: break-word !important; + overflow-wrap: break-word !important; + white-space: normal !important; } .vds-chapter-radio-content { - max-width: 200px !important; + max-width: 200px !important; } .vds-chapter-radio { - align-items: start !important; + align-items: start !important; } @media screen and (max-width: 580px) { - main { - padding-left: .1em !important; - padding-right: .1em !important; - } + main { + padding-left: 0.1em !important; + padding-right: 0.1em !important; + } } main.root { - max-height: 100vh; - overflow-y: scroll; -} \ No newline at end of file + max-height: 100vh; + overflow-y: scroll; +} diff --git a/materialious/tsconfig.json b/materialious/tsconfig.json index f40cc1ff..695fd87f 100644 --- a/materialious/tsconfig.json +++ b/materialious/tsconfig.json @@ -10,12 +10,10 @@ "sourceMap": true, "strict": true, "moduleResolution": "bundler", - "types": [ - "vidstack/svelte" - ] + "types": ["vidstack/svelte"] } // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes // from the referenced tsconfig.json - TypeScript does not merge them in -} \ No newline at end of file +} diff --git a/materialious/vite.config.ts b/materialious/vite.config.ts index 98b67cf8..25ca4a2e 100644 --- a/materialious/vite.config.ts +++ b/materialious/vite.config.ts @@ -8,462 +8,462 @@ export default defineConfig({ SvelteKitPWA({ injectRegister: 'inline', manifest: { - description: "Modern material design for Invidious.", + description: 'Modern material design for Invidious.', icons: [ { - "src": "windows11/SmallTile.scale-100.png", - "sizes": "71x71" + src: 'windows11/SmallTile.scale-100.png', + sizes: '71x71' }, { - "src": "windows11/SmallTile.scale-125.png", - "sizes": "89x89" + src: 'windows11/SmallTile.scale-125.png', + sizes: '89x89' }, { - "src": "windows11/SmallTile.scale-150.png", - "sizes": "107x107" + src: 'windows11/SmallTile.scale-150.png', + sizes: '107x107' }, { - "src": "windows11/SmallTile.scale-200.png", - "sizes": "142x142" + src: 'windows11/SmallTile.scale-200.png', + sizes: '142x142' }, { - "src": "windows11/SmallTile.scale-400.png", - "sizes": "284x284" + src: 'windows11/SmallTile.scale-400.png', + sizes: '284x284' }, { - "src": "windows11/Square150x150Logo.scale-100.png", - "sizes": "150x150" + src: 'windows11/Square150x150Logo.scale-100.png', + sizes: '150x150' }, { - "src": "windows11/Square150x150Logo.scale-125.png", - "sizes": "188x188" + src: 'windows11/Square150x150Logo.scale-125.png', + sizes: '188x188' }, { - "src": "windows11/Square150x150Logo.scale-150.png", - "sizes": "225x225" + src: 'windows11/Square150x150Logo.scale-150.png', + sizes: '225x225' }, { - "src": "windows11/Square150x150Logo.scale-200.png", - "sizes": "300x300" + src: 'windows11/Square150x150Logo.scale-200.png', + sizes: '300x300' }, { - "src": "windows11/Square150x150Logo.scale-400.png", - "sizes": "600x600" + src: 'windows11/Square150x150Logo.scale-400.png', + sizes: '600x600' }, { - "src": "windows11/Wide310x150Logo.scale-100.png", - "sizes": "310x150" + src: 'windows11/Wide310x150Logo.scale-100.png', + sizes: '310x150' }, { - "src": "windows11/Wide310x150Logo.scale-125.png", - "sizes": "388x188" + src: 'windows11/Wide310x150Logo.scale-125.png', + sizes: '388x188' }, { - "src": "windows11/Wide310x150Logo.scale-150.png", - "sizes": "465x225" + src: 'windows11/Wide310x150Logo.scale-150.png', + sizes: '465x225' }, { - "src": "windows11/Wide310x150Logo.scale-200.png", - "sizes": "620x300" + src: 'windows11/Wide310x150Logo.scale-200.png', + sizes: '620x300' }, { - "src": "windows11/Wide310x150Logo.scale-400.png", - "sizes": "1240x600" + src: 'windows11/Wide310x150Logo.scale-400.png', + sizes: '1240x600' }, { - "src": "windows11/LargeTile.scale-100.png", - "sizes": "310x310" + src: 'windows11/LargeTile.scale-100.png', + sizes: '310x310' }, { - "src": "windows11/LargeTile.scale-125.png", - "sizes": "388x388" + src: 'windows11/LargeTile.scale-125.png', + sizes: '388x388' }, { - "src": "windows11/LargeTile.scale-150.png", - "sizes": "465x465" + src: 'windows11/LargeTile.scale-150.png', + sizes: '465x465' }, { - "src": "windows11/LargeTile.scale-200.png", - "sizes": "620x620" + src: 'windows11/LargeTile.scale-200.png', + sizes: '620x620' }, { - "src": "windows11/LargeTile.scale-400.png", - "sizes": "1240x1240" + src: 'windows11/LargeTile.scale-400.png', + sizes: '1240x1240' }, { - "src": "windows11/Square44x44Logo.scale-100.png", - "sizes": "44x44" + src: 'windows11/Square44x44Logo.scale-100.png', + sizes: '44x44' }, { - "src": "windows11/Square44x44Logo.scale-125.png", - "sizes": "55x55" + src: 'windows11/Square44x44Logo.scale-125.png', + sizes: '55x55' }, { - "src": "windows11/Square44x44Logo.scale-150.png", - "sizes": "66x66" + src: 'windows11/Square44x44Logo.scale-150.png', + sizes: '66x66' }, { - "src": "windows11/Square44x44Logo.scale-200.png", - "sizes": "88x88" + src: 'windows11/Square44x44Logo.scale-200.png', + sizes: '88x88' }, { - "src": "windows11/Square44x44Logo.scale-400.png", - "sizes": "176x176" + src: 'windows11/Square44x44Logo.scale-400.png', + sizes: '176x176' }, { - "src": "windows11/StoreLogo.scale-100.png", - "sizes": "50x50" + src: 'windows11/StoreLogo.scale-100.png', + sizes: '50x50' }, { - "src": "windows11/StoreLogo.scale-125.png", - "sizes": "63x63" + src: 'windows11/StoreLogo.scale-125.png', + sizes: '63x63' }, { - "src": "windows11/StoreLogo.scale-150.png", - "sizes": "75x75" + src: 'windows11/StoreLogo.scale-150.png', + sizes: '75x75' }, { - "src": "windows11/StoreLogo.scale-200.png", - "sizes": "100x100" + src: 'windows11/StoreLogo.scale-200.png', + sizes: '100x100' }, { - "src": "windows11/StoreLogo.scale-400.png", - "sizes": "200x200" + src: 'windows11/StoreLogo.scale-400.png', + sizes: '200x200' }, { - "src": "windows11/SplashScreen.scale-100.png", - "sizes": "620x300" + src: 'windows11/SplashScreen.scale-100.png', + sizes: '620x300' }, { - "src": "windows11/SplashScreen.scale-125.png", - "sizes": "775x375" + src: 'windows11/SplashScreen.scale-125.png', + sizes: '775x375' }, { - "src": "windows11/SplashScreen.scale-150.png", - "sizes": "930x450" + src: 'windows11/SplashScreen.scale-150.png', + sizes: '930x450' }, { - "src": "windows11/SplashScreen.scale-200.png", - "sizes": "1240x600" + src: 'windows11/SplashScreen.scale-200.png', + sizes: '1240x600' }, { - "src": "windows11/SplashScreen.scale-400.png", - "sizes": "2480x1200" + src: 'windows11/SplashScreen.scale-400.png', + sizes: '2480x1200' }, { - "src": "windows11/Square44x44Logo.targetsize-16.png", - "sizes": "16x16" + src: 'windows11/Square44x44Logo.targetsize-16.png', + sizes: '16x16' }, { - "src": "windows11/Square44x44Logo.targetsize-20.png", - "sizes": "20x20" + src: 'windows11/Square44x44Logo.targetsize-20.png', + sizes: '20x20' }, { - "src": "windows11/Square44x44Logo.targetsize-24.png", - "sizes": "24x24" + src: 'windows11/Square44x44Logo.targetsize-24.png', + sizes: '24x24' }, { - "src": "windows11/Square44x44Logo.targetsize-30.png", - "sizes": "30x30" + src: 'windows11/Square44x44Logo.targetsize-30.png', + sizes: '30x30' }, { - "src": "windows11/Square44x44Logo.targetsize-32.png", - "sizes": "32x32" + src: 'windows11/Square44x44Logo.targetsize-32.png', + sizes: '32x32' }, { - "src": "windows11/Square44x44Logo.targetsize-36.png", - "sizes": "36x36" + src: 'windows11/Square44x44Logo.targetsize-36.png', + sizes: '36x36' }, { - "src": "windows11/Square44x44Logo.targetsize-40.png", - "sizes": "40x40" + src: 'windows11/Square44x44Logo.targetsize-40.png', + sizes: '40x40' }, { - "src": "windows11/Square44x44Logo.targetsize-44.png", - "sizes": "44x44" + src: 'windows11/Square44x44Logo.targetsize-44.png', + sizes: '44x44' }, { - "src": "windows11/Square44x44Logo.targetsize-48.png", - "sizes": "48x48" + src: 'windows11/Square44x44Logo.targetsize-48.png', + sizes: '48x48' }, { - "src": "windows11/Square44x44Logo.targetsize-60.png", - "sizes": "60x60" + src: 'windows11/Square44x44Logo.targetsize-60.png', + sizes: '60x60' }, { - "src": "windows11/Square44x44Logo.targetsize-64.png", - "sizes": "64x64" + src: 'windows11/Square44x44Logo.targetsize-64.png', + sizes: '64x64' }, { - "src": "windows11/Square44x44Logo.targetsize-72.png", - "sizes": "72x72" + src: 'windows11/Square44x44Logo.targetsize-72.png', + sizes: '72x72' }, { - "src": "windows11/Square44x44Logo.targetsize-80.png", - "sizes": "80x80" + src: 'windows11/Square44x44Logo.targetsize-80.png', + sizes: '80x80' }, { - "src": "windows11/Square44x44Logo.targetsize-96.png", - "sizes": "96x96" + src: 'windows11/Square44x44Logo.targetsize-96.png', + sizes: '96x96' }, { - "src": "windows11/Square44x44Logo.targetsize-256.png", - "sizes": "256x256" + src: 'windows11/Square44x44Logo.targetsize-256.png', + sizes: '256x256' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-16.png", - "sizes": "16x16" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-16.png', + sizes: '16x16' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-20.png", - "sizes": "20x20" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-20.png', + sizes: '20x20' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-24.png", - "sizes": "24x24" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-24.png', + sizes: '24x24' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-30.png", - "sizes": "30x30" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-30.png', + sizes: '30x30' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-32.png", - "sizes": "32x32" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-32.png', + sizes: '32x32' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-36.png", - "sizes": "36x36" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-36.png', + sizes: '36x36' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-40.png", - "sizes": "40x40" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-40.png', + sizes: '40x40' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-44.png", - "sizes": "44x44" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-44.png', + sizes: '44x44' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-48.png", - "sizes": "48x48" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-48.png', + sizes: '48x48' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-60.png", - "sizes": "60x60" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-60.png', + sizes: '60x60' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-64.png", - "sizes": "64x64" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-64.png', + sizes: '64x64' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-72.png", - "sizes": "72x72" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-72.png', + sizes: '72x72' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-80.png", - "sizes": "80x80" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-80.png', + sizes: '80x80' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-96.png", - "sizes": "96x96" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-96.png', + sizes: '96x96' }, { - "src": "windows11/Square44x44Logo.altform-unplated_targetsize-256.png", - "sizes": "256x256" + src: 'windows11/Square44x44Logo.altform-unplated_targetsize-256.png', + sizes: '256x256' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png", - "sizes": "16x16" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png', + sizes: '16x16' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png", - "sizes": "20x20" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png', + sizes: '20x20' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png", - "sizes": "24x24" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png', + sizes: '24x24' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png", - "sizes": "30x30" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png', + sizes: '30x30' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png", - "sizes": "32x32" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png', + sizes: '32x32' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png", - "sizes": "36x36" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png', + sizes: '36x36' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png", - "sizes": "40x40" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png', + sizes: '40x40' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png", - "sizes": "44x44" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png', + sizes: '44x44' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png", - "sizes": "48x48" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png', + sizes: '48x48' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png", - "sizes": "60x60" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png', + sizes: '60x60' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png", - "sizes": "64x64" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png', + sizes: '64x64' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png", - "sizes": "72x72" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png', + sizes: '72x72' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png", - "sizes": "80x80" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png', + sizes: '80x80' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png", - "sizes": "96x96" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png', + sizes: '96x96' }, { - "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png", - "sizes": "256x256" + src: 'windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png', + sizes: '256x256' }, { - "src": "android/android-launchericon-512-512.png", - "sizes": "512x512" + src: 'android/android-launchericon-512-512.png', + sizes: '512x512' }, { - "src": "android/android-launchericon-192-192.png", - "sizes": "192x192" + src: 'android/android-launchericon-192-192.png', + sizes: '192x192' }, { - "src": "android/android-launchericon-144-144.png", - "sizes": "144x144" + src: 'android/android-launchericon-144-144.png', + sizes: '144x144' }, { - "src": "android/android-launchericon-96-96.png", - "sizes": "96x96" + src: 'android/android-launchericon-96-96.png', + sizes: '96x96' }, { - "src": "android/android-launchericon-72-72.png", - "sizes": "72x72" + src: 'android/android-launchericon-72-72.png', + sizes: '72x72' }, { - "src": "android/android-launchericon-48-48.png", - "sizes": "48x48" + src: 'android/android-launchericon-48-48.png', + sizes: '48x48' }, { - "src": "ios/16.png", - "sizes": "16x16" + src: 'ios/16.png', + sizes: '16x16' }, { - "src": "ios/20.png", - "sizes": "20x20" + src: 'ios/20.png', + sizes: '20x20' }, { - "src": "ios/29.png", - "sizes": "29x29" + src: 'ios/29.png', + sizes: '29x29' }, { - "src": "ios/32.png", - "sizes": "32x32" + src: 'ios/32.png', + sizes: '32x32' }, { - "src": "ios/40.png", - "sizes": "40x40" + src: 'ios/40.png', + sizes: '40x40' }, { - "src": "ios/50.png", - "sizes": "50x50" + src: 'ios/50.png', + sizes: '50x50' }, { - "src": "ios/57.png", - "sizes": "57x57" + src: 'ios/57.png', + sizes: '57x57' }, { - "src": "ios/58.png", - "sizes": "58x58" + src: 'ios/58.png', + sizes: '58x58' }, { - "src": "ios/60.png", - "sizes": "60x60" + src: 'ios/60.png', + sizes: '60x60' }, { - "src": "ios/64.png", - "sizes": "64x64" + src: 'ios/64.png', + sizes: '64x64' }, { - "src": "ios/72.png", - "sizes": "72x72" + src: 'ios/72.png', + sizes: '72x72' }, { - "src": "ios/76.png", - "sizes": "76x76" + src: 'ios/76.png', + sizes: '76x76' }, { - "src": "ios/80.png", - "sizes": "80x80" + src: 'ios/80.png', + sizes: '80x80' }, { - "src": "ios/87.png", - "sizes": "87x87" + src: 'ios/87.png', + sizes: '87x87' }, { - "src": "ios/100.png", - "sizes": "100x100" + src: 'ios/100.png', + sizes: '100x100' }, { - "src": "ios/114.png", - "sizes": "114x114" + src: 'ios/114.png', + sizes: '114x114' }, { - "src": "ios/120.png", - "sizes": "120x120" + src: 'ios/120.png', + sizes: '120x120' }, { - "src": "ios/128.png", - "sizes": "128x128" + src: 'ios/128.png', + sizes: '128x128' }, { - "src": "ios/144.png", - "sizes": "144x144" + src: 'ios/144.png', + sizes: '144x144' }, { - "src": "ios/152.png", - "sizes": "152x152" + src: 'ios/152.png', + sizes: '152x152' }, { - "src": "ios/167.png", - "sizes": "167x167" + src: 'ios/167.png', + sizes: '167x167' }, { - "src": "ios/180.png", - "sizes": "180x180" + src: 'ios/180.png', + sizes: '180x180' }, { - "src": "ios/192.png", - "sizes": "192x192" + src: 'ios/192.png', + sizes: '192x192' }, { - "src": "ios/256.png", - "sizes": "256x256" + src: 'ios/256.png', + sizes: '256x256' }, { - "src": "ios/512.png", - "sizes": "512x512" + src: 'ios/512.png', + sizes: '512x512' }, { - "src": "ios/1024.png", - "sizes": "1024x1024" + src: 'ios/1024.png', + sizes: '1024x1024' } ], - background_color: "#22005d", - theme_color: "#efb0ff" + background_color: '#22005d', + theme_color: '#efb0ff' } }), vidstack(), sveltekit() - ], + ] });