summaryrefslogtreecommitdiff
path: root/src/lib/stores
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/stores')
-rw-r--r--src/lib/stores/playlists.ts123
-rw-r--r--src/lib/stores/subscriptions.ts65
2 files changed, 188 insertions, 0 deletions
diff --git a/src/lib/stores/playlists.ts b/src/lib/stores/playlists.ts
new file mode 100644
index 0000000..ee516dc
--- /dev/null
+++ b/src/lib/stores/playlists.ts
@@ -0,0 +1,123 @@
+import { writable } from 'svelte/store';
+import { get, set } from 'idb-keyval';
+
+export interface PlaylistVideo {
+ videoId: string;
+ title: string;
+ author: string;
+ authorId: string;
+ thumbnail: string;
+ lengthSeconds: number;
+}
+
+export interface Playlist {
+ id: string;
+ name: string;
+ videos: PlaylistVideo[];
+ createdAt: number;
+ updatedAt: number;
+}
+
+const STORAGE_KEY = 'actualyt-playlists';
+
+function generateId(): string {
+ return Date.now().toString(36) + Math.random().toString(36).substring(2);
+}
+
+function createPlaylistStore() {
+ const { subscribe, set: setStore, update } = writable<Playlist[]>([]);
+ let initialized = false;
+
+ async function init() {
+ if (initialized) return;
+ try {
+ const stored = await get<Playlist[]>(STORAGE_KEY);
+ if (stored) {
+ setStore(stored);
+ }
+ initialized = true;
+ } catch (e) {
+ console.error('Failed to load playlists:', e);
+ }
+ }
+
+ async function persist(playlists: Playlist[]) {
+ try {
+ await set(STORAGE_KEY, playlists);
+ } catch (e) {
+ console.error('Failed to save playlists:', e);
+ }
+ }
+
+ return {
+ subscribe,
+ init,
+ create: async (name: string): Promise<string> => {
+ const id = generateId();
+ const now = Date.now();
+ const newPlaylist: Playlist = {
+ id,
+ name,
+ videos: [],
+ createdAt: now,
+ updatedAt: now
+ };
+ update(playlists => {
+ const newPlaylists = [...playlists, newPlaylist];
+ persist(newPlaylists);
+ return newPlaylists;
+ });
+ return id;
+ },
+ delete: async (id: string) => {
+ update(playlists => {
+ const newPlaylists = playlists.filter(p => p.id !== id);
+ persist(newPlaylists);
+ return newPlaylists;
+ });
+ },
+ rename: async (id: string, name: string) => {
+ update(playlists => {
+ const newPlaylists = playlists.map(p =>
+ p.id === id ? { ...p, name, updatedAt: Date.now() } : p
+ );
+ persist(newPlaylists);
+ return newPlaylists;
+ });
+ },
+ addVideo: async (playlistId: string, video: PlaylistVideo) => {
+ update(playlists => {
+ const newPlaylists = playlists.map(p => {
+ if (p.id !== playlistId) return p;
+ if (p.videos.some(v => v.videoId === video.videoId)) return p;
+ return {
+ ...p,
+ videos: [...p.videos, video],
+ updatedAt: Date.now()
+ };
+ });
+ persist(newPlaylists);
+ return newPlaylists;
+ });
+ },
+ removeVideo: async (playlistId: string, videoId: string) => {
+ update(playlists => {
+ const newPlaylists = playlists.map(p => {
+ if (p.id !== playlistId) return p;
+ return {
+ ...p,
+ videos: p.videos.filter(v => v.videoId !== videoId),
+ updatedAt: Date.now()
+ };
+ });
+ persist(newPlaylists);
+ return newPlaylists;
+ });
+ },
+ getById: (playlists: Playlist[], id: string): Playlist | undefined => {
+ return playlists.find(p => p.id === id);
+ }
+ };
+}
+
+export const playlists = createPlaylistStore();
diff --git a/src/lib/stores/subscriptions.ts b/src/lib/stores/subscriptions.ts
new file mode 100644
index 0000000..91f3d36
--- /dev/null
+++ b/src/lib/stores/subscriptions.ts
@@ -0,0 +1,65 @@
+import { writable } from 'svelte/store';
+import { get, set } from 'idb-keyval';
+import type { VideoThumbnail } from '$lib/api/youtube';
+
+export interface Subscription {
+ channelId: string;
+ channelName: string;
+ thumbnail: string;
+}
+
+const STORAGE_KEY = 'actualyt-subscriptions';
+
+function createSubscriptionStore() {
+ const { subscribe, set: setStore, update } = writable<Subscription[]>([]);
+ let initialized = false;
+
+ async function init() {
+ if (initialized) return;
+ try {
+ const stored = await get<Subscription[]>(STORAGE_KEY);
+ if (stored) {
+ setStore(stored);
+ }
+ initialized = true;
+ } catch (e) {
+ console.error('Failed to load subscriptions:', e);
+ }
+ }
+
+ async function persist(subs: Subscription[]) {
+ try {
+ await set(STORAGE_KEY, subs);
+ } catch (e) {
+ console.error('Failed to save subscriptions:', e);
+ }
+ }
+
+ return {
+ subscribe,
+ init,
+ add: async (channelId: string, channelName: string, thumbnails: VideoThumbnail[]) => {
+ update(subs => {
+ if (subs.some(s => s.channelId === channelId)) {
+ return subs;
+ }
+ const thumbnail = thumbnails[0]?.url || '';
+ const newSubs = [...subs, { channelId, channelName, thumbnail }];
+ persist(newSubs);
+ return newSubs;
+ });
+ },
+ remove: async (channelId: string) => {
+ update(subs => {
+ const newSubs = subs.filter(s => s.channelId !== channelId);
+ persist(newSubs);
+ return newSubs;
+ });
+ },
+ isSubscribed: (subs: Subscription[], channelId: string): boolean => {
+ return subs.some(s => s.channelId === channelId);
+ }
+ };
+}
+
+export const subscriptions = createSubscriptionStore();