Experiment to rebuild Diffuse using web applets.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at cb8a125c0ec7af04dfca6d31ff6bb38b2cd890bc 96 lines 2.4 kB view raw
1import type { Track } from "@applets/core/types.js"; 2import type { Item, State } from "./types"; 3import { arrayShuffle, expose, transfer } from "@scripts/common.ts"; 4 5//////////////////////////////////////////// 6// STATE 7//////////////////////////////////////////// 8 9const QUEUE_SIZE = 25; 10 11const internal: { pool: Track[] } = { 12 pool: [], 13}; 14 15//////////////////////////////////////////// 16// ACTIONS 17//////////////////////////////////////////// 18const actions = expose({ 19 add, 20 pool, 21 shift, 22 unshift, 23}); 24 25export type Actions = typeof actions; 26 27// Actions 28 29function add(state: State, items: Item[]): State { 30 return transfer({ ...state, future: [...state.future, ...items] }); 31} 32 33function pool(state: State, tracks: Track[]): State { 34 internal.pool = tracks; 35 36 // TODO: If the pool changes, only remove non-existing tracks 37 // instead of resetting the whole future queue. 38 // 39 // What about past queue items? 40 41 state = fill({ ...state, future: [] }); 42 43 // Automatically insert track if there isn't any 44 if (!state.now) return shift(state); 45 return transfer(state); 46} 47 48function shift(state: State): State { 49 const now = state.future[0] || null; 50 const future = state.future.slice(1); 51 const past = state.now ? [...state.past, state.now] : state.past; 52 const filled = fill({ past, now, future }); 53 54 return transfer(filled); 55} 56 57function unshift(state: State): State { 58 if (state.past.length === 0) return state; 59 60 const past = [...state.past]; 61 const [last] = past.splice(past.length - 1, 1); 62 const now = last ?? null; 63 const future = state.now ? [state.now, ...state.future] : state.future; 64 65 return transfer({ past, now, future }); 66} 67 68// 🛠️ 69 70// TODO: Most likely there's a more performant solution 71function fill(state: State): State { 72 if (state.future.length >= QUEUE_SIZE) return state; 73 74 let reducedPool = internal.pool.reduce( 75 ({ past, pool }: { past: Set<string>; pool: Track[] }, track: Track) => { 76 if (past.has(track.id)) 77 return { 78 past: past.difference(new Set(track.id)), 79 pool, 80 }; 81 82 return { 83 past, 84 pool: [...pool, track], 85 }; 86 }, 87 { past: new Set(state.past.map((t) => t.id)), pool: [] }, 88 ).pool; 89 90 if (reducedPool.length === 0) { 91 reducedPool = internal.pool; 92 } 93 94 const poolSelection = arrayShuffle(reducedPool).slice(0, QUEUE_SIZE - state.future.length); 95 return add(state, poolSelection); 96}