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 107 lines 3.2 kB view raw
1import * as Uint8 from "uint8arrays"; 2import * as Comlink from "comlink"; 3import { xxh32 } from "xxh32"; 4import { getTransferables } from "@okikio/transferables"; 5 6import type { Track } from "@applets/core/types"; 7 8// export { SharedWorkerPolyfill as SharedWorker } from "@okikio/sharedworker"; 9export const SharedWorker = globalThis.SharedWorker; 10 11export function arrayShuffle<T>(array: Array<T>): Array<T> { 12 if (array.length === 0) { 13 return []; 14 } 15 16 array = [...array]; 17 18 for (let index = array.length - 1; index > 0; index--) { 19 const randArr = crypto.getRandomValues(new Uint32Array(1)); 20 const randVal = randArr[0] / 2 ** 32; 21 const newIndex = Math.floor(randVal * (index + 1)); 22 [array[index], array[newIndex]] = [array[newIndex], array[index]]; 23 } 24 25 return array; 26} 27 28export function cleanUndefinedValuesForTracks(tracks: Track[]): Track[] { 29 return tracks.map((track) => { 30 const t = { ...track }; 31 32 if (t.tags) { 33 if ("album" in t.tags && t.tags.album === undefined) delete t.tags.album; 34 if ("artist" in t.tags && t.tags.artist === undefined) delete t.tags.artist; 35 if ("genre" in t.tags && t.tags.genre === undefined) delete t.tags.genre; 36 if ("year" in t.tags && t.tags.year === undefined) delete t.tags.year; 37 38 if ("of" in t.tags.disc && t.tags.disc.of === undefined) delete t.tags.disc.of; 39 if ("of" in t.tags.track && t.tags.track.of === undefined) delete t.tags.track.of; 40 } 41 42 return t; 43 }); 44} 45 46export function comparable(value: unknown) { 47 return xxh32(JSON.stringify(value)); 48} 49 50export function endpoint<T extends Record<string, any>>(ini: Comlink.Endpoint) { 51 const e = Comlink.wrap<T>(ini); 52 if ("start" in ini && typeof ini.start === "function") ini.start(); 53 return e; 54} 55 56export function expose<T extends Record<string, any>>(actions: T): T { 57 if (globalThis.SharedWorkerGlobalScope && self instanceof SharedWorkerGlobalScope) { 58 self.onconnect = (event: MessageEvent) => { 59 const port = event.ports[0]; 60 Comlink.expose(actions, port); 61 port.start(); 62 }; 63 64 (self as any).connected = true; 65 } else { 66 Comlink.expose(actions, self); 67 } 68 69 return actions; 70} 71 72export function groupTracksPerScheme( 73 tracks: Track[], 74 initial: Record<string, Track[]> = {}, 75): Record<string, Track[]> { 76 return tracks.reduce((acc: Record<string, Track[]>, track: Track) => { 77 const scheme = track.uri.split(":", 1)[0]; 78 return { ...acc, [scheme]: [...(acc[scheme] || []), track] }; 79 }, initial); 80} 81 82export function inIframe() { 83 return window.self !== window.top; 84} 85 86export function isPrimitive(test: unknown) { 87 return test !== Object(test); 88} 89 90export function jsonDecode<T>(a: any): T { 91 return JSON.parse(new TextDecoder().decode(a)); 92} 93 94export function jsonEncode<T>(a: T): Uint8Array { 95 return new TextEncoder().encode(JSON.stringify(a)); 96} 97 98export async function trackArtworkCacheId(track: Track): Promise<string> { 99 return await crypto.subtle 100 .digest("SHA-256", new TextEncoder().encode(track.uri)) 101 .then((a) => Uint8.toString(new Uint8Array(a), "base64url")); 102} 103 104export function transfer<T = unknown>(a: T) { 105 const b = getTransferables(a); 106 return Comlink.transfer(a, b); 107}