fix: minor memory leaks, force remove unused dependencies, make banner show all releases

This commit is contained in:
ThaUnknown 2025-05-02 19:25:58 +02:00
parent 4da12bfd5d
commit eee9c549ab
No known key found for this signature in database
11 changed files with 51 additions and 23 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "ui", "name": "ui",
"version": "6.1.11", "version": "6.1.12",
"license": "BUSL-1.1", "license": "BUSL-1.1",
"private": true, "private": true,
"packageManager": "pnpm@9.14.4", "packageManager": "pnpm@9.14.4",

1
src/app.d.ts vendored
View file

@ -101,6 +101,7 @@ export interface Native {
updateProgress: (cb: (progress: number) => void) => Promise<void> updateProgress: (cb: (progress: number) => void) => Promise<void>
spawnPlayer: (url: string) => Promise<void> spawnPlayer: (url: string) => Promise<void>
setHideToTray: (enabled: boolean) => Promise<void> setHideToTray: (enabled: boolean) => Promise<void>
transparency: (enabled: boolean) => Promise<void>
isApp: boolean isApp: boolean
version: () => Promise<string> version: () => Promise<string>
} }

View file

@ -1,7 +1,7 @@
<script lang='ts' context='module'> <script lang='ts' context='module'>
import { client, currentSeason, currentYear } from '$lib/modules/anilist' import { client, currentSeason, currentYear } from '$lib/modules/anilist'
const query = client.search({ sort: ['POPULARITY_DESC'], perPage: 15, onList: false, season: currentSeason, seasonYear: currentYear, statusNot: ['NOT_YET_RELEASED'] }, true) const query = client.search({ sort: ['POPULARITY_DESC'], perPage: 15, season: currentSeason, seasonYear: currentYear, statusNot: ['NOT_YET_RELEASED'] }, true)
query.subscribe(() => undefined) // this is hacky as shit, but prevents query from re-running query.subscribe(() => undefined) // this is hacky as shit, but prevents query from re-running
</script> </script>

View file

@ -71,28 +71,29 @@
let dragged: HTMLDivElement | null = null let dragged: HTMLDivElement | null = null
function draggable (node: HTMLDivElement, code: KeyCode) { function draggable (node: HTMLDivElement, code: KeyCode) {
const ctrl = new AbortController()
let drag = false let drag = false
node.addEventListener('dragstart', ({ target: _target }) => { node.addEventListener('dragstart', ({ target: _target }) => {
const target = _target as HTMLDivElement const target = _target as HTMLDivElement
dragged = target dragged = target
target.classList.add('transparent') target.classList.add('transparent')
drag = true drag = true
}) }, { signal: ctrl.signal })
node.addEventListener('dragend', ({ target: _target }) => { node.addEventListener('dragend', ({ target: _target }) => {
const target = _target as HTMLDivElement const target = _target as HTMLDivElement
target.classList.remove('transparent') target.classList.remove('transparent')
drag = false drag = false
}) }, { signal: ctrl.signal })
node.addEventListener('dragover', (e) => { node.addEventListener('dragover', (e) => {
const target = e.target as HTMLDivElement const target = e.target as HTMLDivElement
e.dataTransfer!.dropEffect = 'move' e.dataTransfer!.dropEffect = 'move'
e.preventDefault() e.preventDefault()
if (!drag) target.classList.add('transparent') if (!drag) target.classList.add('transparent')
}) }, { signal: ctrl.signal })
node.addEventListener('dragleave', ({ target: _target }) => { node.addEventListener('dragleave', ({ target: _target }) => {
const target = _target as HTMLDivElement const target = _target as HTMLDivElement
if (!drag) target.classList.remove('transparent') if (!drag) target.classList.remove('transparent')
}) }, { signal: ctrl.signal })
node.addEventListener('drop', ({ target: _target }) => { node.addEventListener('drop', ({ target: _target }) => {
const target = _target as HTMLDivElement const target = _target as HTMLDivElement
target.style.opacity = '' target.style.opacity = ''
@ -106,7 +107,9 @@
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete $binds[targetcode] delete $binds[targetcode]
} }
}) }, { signal: ctrl.signal })
return { destroy: () => ctrl.abort() }
} }
</script> </script>

View file

@ -84,6 +84,7 @@ export default Object.assign<Native, Partial<Native>>({
cachedTorrents: async () => ['40a9047de61859035659e449d7b84286934486b0'], cachedTorrents: async () => ['40a9047de61859035659e449d7b84286934486b0'],
spawnPlayer: () => sleep(rnd(100_000)), spawnPlayer: () => sleep(rnd(100_000)),
setHideToTray: async () => undefined, setHideToTray: async () => undefined,
transparency: async () => undefined,
updateProgress: async (cb: (progress: number) => void) => undefined, updateProgress: async (cb: (progress: number) => void) => undefined,
torrentStats: async (): Promise<TorrentInfo> => ({ peers: rnd(), seeders: rnd(), leechers: rnd(), progress: Math.random(), down: rnd(100000000), up: rnd(100000000), name: 'Amebku.webm', downloaded: rnd(100000), hash: '1234567890abcdef', size: 1234567890, eta: rnd() }), torrentStats: async (): Promise<TorrentInfo> => ({ peers: rnd(), seeders: rnd(), leechers: rnd(), progress: Math.random(), down: rnd(100000000), up: rnd(100000000), name: 'Amebku.webm', downloaded: rnd(100000), hash: '1234567890abcdef', size: 1234567890, eta: rnd() }),
torrents: async (): Promise<TorrentInfo[]> => [{ peers: rnd(), seeders: rnd(), leechers: rnd(), progress: Math.random(), down: rnd(100000000), up: rnd(100000000), name: 'Amebku.webm', downloaded: rnd(100000), hash: '1234567890abcdef', size: 1234567890, eta: rnd() }] torrents: async (): Promise<TorrentInfo[]> => [{ peers: rnd(), seeders: rnd(), leechers: rnd(), progress: Math.random(), down: rnd(100000000), up: rnd(100000000), name: 'Amebku.webm', downloaded: rnd(100000), hash: '1234567890abcdef', size: 1234567890, eta: rnd() }]

View file

@ -50,6 +50,7 @@ export function keywrap (cb: (_: KeyboardEvent) => unknown = noop) {
* Adds click event listener to the specified node. * Adds click event listener to the specified node.
*/ */
export function click (node: HTMLElement, cb: (_: Event) => unknown = noop) { export function click (node: HTMLElement, cb: (_: Event) => unknown = noop) {
const ctrl = new AbortController()
node.tabIndex = 0 node.tabIndex = 0
node.role = 'button' node.role = 'button'
node.addEventListener('click', e => { node.addEventListener('click', e => {
@ -57,20 +58,23 @@ export function click (node: HTMLElement, cb: (_: Event) => unknown = noop) {
e.preventDefault() e.preventDefault()
navigator.vibrate(15) navigator.vibrate(15)
cb(e) cb(e)
}) }, { signal: ctrl.signal })
node.addEventListener('keydown', e => { node.addEventListener('keydown', e => {
if (e.key === 'Enter' && intputType.value === 'dpad') { if (e.key === 'Enter' && intputType.value === 'dpad') {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
cb(e) cb(e)
} }
}) }, { signal: ctrl.signal })
return { destroy: () => ctrl.abort() }
} }
/** /**
* Adds hover and click event listeners to the specified node. * Adds hover and click event listeners to the specified node.
*/ */
export function hover (node: HTMLElement, [cb = noop, hoverUpdate = noop]: [typeof noop, (_: boolean) => void]) { export function hover (node: HTMLElement, [cb = noop, hoverUpdate = noop]: [typeof noop, (_: boolean) => void]) {
const ctrl = new AbortController()
node.addEventListener('wheel', e => { node.addEventListener('wheel', e => {
// cheap way to update hover state on scroll // cheap way to update hover state on scroll
if (document.elementsFromPoint(e.clientX, e.clientY).includes(node)) { if (document.elementsFromPoint(e.clientX, e.clientY).includes(node)) {
@ -80,14 +84,14 @@ export function hover (node: HTMLElement, [cb = noop, hoverUpdate = noop]: [type
} else { } else {
hoverUpdate(false) hoverUpdate(false)
} }
}, { passive: true }) }, { passive: true, signal: ctrl.signal })
node.tabIndex = 0 node.tabIndex = 0
node.role = 'button' node.role = 'button'
node.addEventListener('pointerenter', () => { node.addEventListener('pointerenter', () => {
lastHoverElement?.(false) lastHoverElement?.(false)
hoverUpdate(true) hoverUpdate(true)
if (intputType.value === 'mouse') lastHoverElement = hoverUpdate if (intputType.value === 'mouse') lastHoverElement = hoverUpdate
}) }, { signal: ctrl.signal })
node.addEventListener('click', e => { node.addEventListener('click', e => {
e.stopPropagation() e.stopPropagation()
if (intputType.value === 'dpad') return if (intputType.value === 'dpad') return
@ -100,7 +104,7 @@ export function hover (node: HTMLElement, [cb = noop, hoverUpdate = noop]: [type
} else { } else {
lastHoverElement = hoverUpdate lastHoverElement = hoverUpdate
} }
}) }, { signal: ctrl.signal })
node.addEventListener('keydown', (e: KeyboardEvent) => { node.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.key === 'Enter' && intputType.value === 'dpad') { if (e.key === 'Enter' && intputType.value === 'dpad') {
e.stopPropagation() e.stopPropagation()
@ -113,16 +117,18 @@ export function hover (node: HTMLElement, [cb = noop, hoverUpdate = noop]: [type
lastHoverElement = hoverUpdate lastHoverElement = hoverUpdate
} }
} }
}) }, { signal: ctrl.signal })
node.addEventListener('pointerleave', () => { node.addEventListener('pointerleave', () => {
if (intputType.value !== 'touch') hoverUpdate(false) if (intputType.value !== 'touch') hoverUpdate(false)
}) }, { signal: ctrl.signal })
node.addEventListener('pointermove', () => { node.addEventListener('pointermove', () => {
if (intputType.value === 'touch') hoverUpdate(false) if (intputType.value === 'touch') hoverUpdate(false)
}) }, { signal: ctrl.signal })
node.addEventListener('drag', () => { node.addEventListener('drag', () => {
if (intputType.value === 'mouse') hoverUpdate(false) if (intputType.value === 'mouse') hoverUpdate(false)
}) }, { signal: ctrl.signal })
return { destroy: () => ctrl.abort() }
} }
interface ElementPosition { element: HTMLElement, x: number, y: number, inViewport: boolean } interface ElementPosition { element: HTMLElement, x: number, y: number, inViewport: boolean }
@ -275,16 +281,18 @@ export function dragScroll (node: HTMLElement) {
let deltaX = 0 let deltaX = 0
let deltaY = 0 let deltaY = 0
const ctrl = new AbortController()
node.addEventListener('mousedown', e => { node.addEventListener('mousedown', e => {
isDragging = true isDragging = true
x = e.clientX x = e.clientX
y = e.clientY y = e.clientY
deltaX = 0 deltaX = 0
deltaY = 0 deltaY = 0
}) }, { signal: ctrl.signal })
node.addEventListener('click', e => { node.addEventListener('click', e => {
isDragging = false isDragging = false
}) }, { signal: ctrl.signal })
node.addEventListener('mousemove', e => { node.addEventListener('mousemove', e => {
if (!isDragging) return true if (!isDragging) return true
@ -296,13 +304,15 @@ export function dragScroll (node: HTMLElement) {
if (deltaX > 15 || deltaY > 15) { if (deltaX > 15 || deltaY > 15) {
e.target?.dispatchEvent(new MouseEvent('drag', { bubbles: true })) e.target?.dispatchEvent(new MouseEvent('drag', { bubbles: true }))
} }
}) }, { signal: ctrl.signal })
node.addEventListener('mouseleave', () => { node.addEventListener('mouseleave', () => {
isDragging = false isDragging = false
}) }, { signal: ctrl.signal })
node.addEventListener('mouseup', () => { node.addEventListener('mouseup', () => {
isDragging = false isDragging = false
}) }, { signal: ctrl.signal })
return { destroy: () => ctrl.abort() }
} }

View file

@ -10,5 +10,6 @@ settings.subscribe(settings => {
const { torrentPersist, torrentDHT, torrentStreamedDownload, torrentSpeed, maxConns, torrentPort, dhtPort, torrentPeX } = settings const { torrentPersist, torrentDHT, torrentStreamedDownload, torrentSpeed, maxConns, torrentPort, dhtPort, torrentPeX } = settings
native.updateSettings({ torrentPersist, torrentDHT, torrentStreamedDownload, torrentSpeed, maxConns, torrentPort, dhtPort, torrentPeX }) native.updateSettings({ torrentPersist, torrentDHT, torrentStreamedDownload, torrentSpeed, maxConns, torrentPort, dhtPort, torrentPeX })
native.setHideToTray(settings.hideToTray) native.setHideToTray(settings.hideToTray)
native.transparency(settings.idleAnimation)
if (settings.enableDoH) native.setDOH(settings.doHURL) if (settings.enableDoH) native.setDOH(settings.doHURL)
}) })

1
src/patches/empty.cjs Normal file
View file

@ -0,0 +1 @@
module.exports = {}

View file

@ -58,8 +58,8 @@
</SettingCard> </SettingCard>
<div class='font-weight-bold text-xl font-bold'>UI Settings</div> <div class='font-weight-bold text-xl font-bold'>UI Settings</div>
<SettingCard title='Idle Animation' description='Enable/Disable the 3d idle animation.'> <SettingCard title='Idle Animation' description='Enable/Disable the 3d idle animation. Changing this setting will restart the app.'>
<Switch bind:checked={$settings.idleAnimation} /> <Switch bind:checked={$settings.idleAnimation} on:click={native.restart} />
</SettingCard> </SettingCard>
{/if} {/if}
</div> </div>

View file

@ -33,6 +33,7 @@
"include": [ "include": [
"src/service-worker/index.ts", "src/service-worker/index.ts",
"src/**/*.js", "src/**/*.js",
"src/**/*.cjs",
"src/**/*.ts", "src/**/*.ts",
"src/**/*.d.ts", "src/**/*.d.ts",
"src/**/*.svelte", "src/**/*.svelte",

View file

@ -15,6 +15,16 @@ export default defineConfig({
} }
}) })
], ],
resolve: {
alias: {
// thank you bottleneck for importing useless modules
'./RedisConnection': resolve(__dirname, 'src/patches/empty.cjs'),
'./RedisConnection.js': resolve(__dirname, 'src/patches/empty.cjs'),
'./RedisDatastore': resolve(__dirname, 'src/patches/empty.cjs'),
'./IORedisConnection': resolve(__dirname, 'src/patches/empty.cjs'),
'./Scripts': resolve(__dirname, 'src/patches/empty.cjs')
}
},
server: { port: 7344 }, server: { port: 7344 },
build: { build: {
target: 'esnext' target: 'esnext'