Implemeneted favourited system

This commit is contained in:
WardPearce
2025-12-08 23:03:07 +13:00
parent 42b6558103
commit e39fce51e2
10 changed files with 105 additions and 10 deletions
+12 -2
View File
@@ -1,16 +1,17 @@
{
"name": "Materialious",
"version": "1.12.0",
"version": "1.12.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "Materialious",
"version": "1.12.0",
"version": "1.12.3",
"license": "MIT",
"dependencies": {
"@capacitor-community/electron": "^5.0.0",
"bgutils-js": "^3.2.0",
"capacitor-nodejs": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.9/capacitor-nodejs.tgz",
"chokidar": "~5.0.0",
"electron-is-dev": "~2.0.0",
"electron-serve": "~3.0.0",
@@ -1885,6 +1886,15 @@
"node": ">= 0.4"
}
},
"node_modules/capacitor-nodejs": {
"version": "1.0.0-beta.9",
"resolved": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.9/capacitor-nodejs.tgz",
"integrity": "sha512-4EU/QBolfuyHiMtwd1nxZ4wsK243tGE4VttKvVBG+x1yQuK9EIlEf3lbRjFXfjrJMTZNCqaP6glmdfj9Zo7KVg==",
"license": "MIT",
"peerDependencies": {
"@capacitor/core": ">=7.0.0"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+2 -1
View File
@@ -24,6 +24,7 @@
"dependencies": {
"@capacitor-community/electron": "^5.0.0",
"bgutils-js": "^3.2.0",
"capacitor-nodejs": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.9/capacitor-nodejs.tgz",
"chokidar": "~5.0.0",
"electron-is-dev": "~2.0.0",
"electron-serve": "~3.0.0",
@@ -43,4 +44,4 @@
"capacitor",
"electron"
]
}
}
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const CapacitorNodejs = require('../../../node_modules/capacitor-nodejs/electron/dist/plugin.js');
module.exports = {
CapacitorNodejs,
}
+9 -2
View File
@@ -1,12 +1,12 @@
{
"name": "materialious",
"version": "1.12.0",
"version": "1.12.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "materialious",
"version": "1.12.0",
"version": "1.12.3",
"hasInstallScript": true,
"dependencies": {
"@capacitor-community/electron": "^5.0.1",
@@ -25,6 +25,7 @@
"bgutils-js": "^3.2.0",
"capacitor-nodejs": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.9/capacitor-nodejs.tgz",
"dayjs": "^1.11.19",
"dexie": "^4.2.1",
"fuse.js": "^7.0.0",
"googlevideo": "^4.0.4",
"he": "^1.2.0",
@@ -5669,6 +5670,12 @@
"integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==",
"license": "MIT"
},
"node_modules/dexie": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/dexie/-/dexie-4.2.1.tgz",
"integrity": "sha512-Ckej0NS6jxQ4Po3OrSQBFddayRhTCic2DoCAG5zacOfOVB9P2Q5Xc5uL/nVa7ZVs+HdMnvUPzLFCB/JwpB6Csg==",
"license": "Apache-2.0"
},
"node_modules/dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
+2 -1
View File
@@ -57,6 +57,7 @@
"bgutils-js": "^3.2.0",
"capacitor-nodejs": "https://github.com/hampoelz/capacitor-nodejs/releases/download/v1.0.0-beta.9/capacitor-nodejs.tgz",
"dayjs": "^1.11.19",
"dexie": "^4.2.1",
"fuse.js": "^7.0.0",
"googlevideo": "^4.0.4",
"he": "^1.2.0",
@@ -73,4 +74,4 @@
"svelte-infinite-loading": "^1.4.0",
"youtubei.js": "^16.0.1"
}
}
}
+6
View File
@@ -23,6 +23,9 @@ export interface VideoBase {
lengthSeconds: number;
viewCountText: string;
viewCount?: number;
// Means it was given preference in rankings due to
// a users settings
promotedBy?: 'favourited';
}
export interface ResolvedUrl {
@@ -205,6 +208,9 @@ export interface PlaylistPageVideo extends Omit<PlaylistVideo, 'type'> {
indexId: string;
authorId: string;
viewCount: number;
// Means it was given preference in rankings due to
// a users settings
promotedBy?: 'favourited';
}
export interface ChannelContentVideos {
@@ -229,6 +229,10 @@
<p>{video.author}</p>
{/if}
{#if video.promotedBy === 'favourited'}
<i>star</i>
{/if}
{#if !('publishedText' in video) && 'viewCountText' in video}
{video.viewCountText ?? cleanNumber(video.viewCount ?? 0)}
@@ -6,6 +6,8 @@
import { truncate } from '$lib/misc';
import { authStore, interfaceLowBandwidthMode, isAndroidTvStore } from '$lib/store';
import { _ } from '$lib/i18n';
import { localDb } from '$lib/dexie';
import { onMount } from 'svelte';
let {
video,
@@ -13,6 +15,16 @@
hideSubscribe = false
}: { video: VideoPlay; subscribed?: boolean; hideSubscribe?: boolean } = $props();
let favoritedChannel = $state(false);
const favoriteChannelItem = localDb.favouriteChannels.filter((item) => {
return item.channelId === video.authorId;
});
onMount(async () => {
favoritedChannel = (await favoriteChannelItem.count()) > 0;
});
async function toggleSubscribed() {
if (subscribed) {
await deleteUnsubscribe(video.authorId);
@@ -22,6 +34,16 @@
subscribed = !subscribed;
}
async function toggleFavourited() {
if (favoritedChannel) {
await favoriteChannelItem.delete();
favoritedChannel = false;
} else {
await localDb.favouriteChannels.add({ channelId: video.authorId, created: new Date() });
favoritedChannel = true;
}
}
</script>
<nav>
@@ -56,6 +78,16 @@
{$_('unsubscribe')}
{/if}
</button>
<button
class:inverse-surface={!favoritedChannel}
class:border={favoritedChannel}
onclick={toggleFavourited}
>
<i>star</i>
<div class="tooltip">
{favoritedChannel ? $_('unfavouriteChannel') : $_('favouriteChannel')}
</div>
</button>
{:else}
<button class="inverse-surface" disabled>
{$_('subscribe')}
+3 -1
View File
@@ -200,5 +200,7 @@
"titleOnly": "Title only"
}
},
"subscribe": "Subscribe"
"subscribe": "Subscribe",
"favouriteChannel": "Favourite channel",
"unfavouriteChannel": "Unfavourite channel"
}
@@ -1,10 +1,36 @@
import { getFeed } from '$lib/api/index';
import type { PlaylistPageVideo, Video, VideoBase } from '$lib/api/model';
import { localDb } from '$lib/dexie';
import { excludeDuplicateFeeds } from '$lib/misc';
import { feedCacheStore } from '$lib/store';
import { error } from '@sveltejs/kit';
import { get } from 'svelte/store';
async function sortVideosByFavourites(
videos: (VideoBase | Video | PlaylistPageVideo)[]
): Promise<(VideoBase | Video | PlaylistPageVideo)[]> {
const favouritedChannels = (await localDb.favouriteChannels.toArray()).map(
(channel) => channel.channelId
);
if (favouritedChannels.length === 0) {
return videos;
}
const rearrangedVideos: (VideoBase | Video | PlaylistPageVideo)[] = [];
videos.forEach((video) => {
if (favouritedChannels.includes(video.authorId)) {
video.promotedBy = 'favourited';
rearrangedVideos.unshift(video);
} else {
rearrangedVideos.push(video);
}
});
return rearrangedVideos;
}
export async function load() {
let videos = get(feedCacheStore).subscription;
@@ -16,12 +42,16 @@ export async function load() {
error(500, errorMessage);
}
videos = [...feeds.notifications, ...feeds.videos];
videos = await sortVideosByFavourites([...feeds.notifications, ...feeds.videos]);
feedCacheStore.set({ ...get(feedCacheStore), subscription: videos });
} else {
await getFeed(100, 1).then((feeds) => {
const newVideos = [...feeds.notifications, ...feeds.videos, ...videos];
await getFeed(100, 1).then(async (feeds) => {
const newVideos = await sortVideosByFavourites([
...feeds.notifications,
...feeds.videos,
...videos
]);
feedCacheStore.set({
...get(feedCacheStore),
subscription: excludeDuplicateFeeds(videos, newVideos) as (