Skip to content

Commit

Permalink
feat: implement audio preload management with IntersectionObserver
Browse files Browse the repository at this point in the history
  • Loading branch information
purocean committed Jan 13, 2025
1 parent 2ee77bf commit 1b8b2e4
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/renderer/plugins/markdown-link/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export function convertResourceState (currentFile: PathItem, state: StateCore, b
} else if (RE_AUDIO.test(fileName)) {
token.tag = 'audio'
token.type = 'media'
token.attrSet('preload', 'none')
} else {
token.attrSet(DOM_ATTR_NAME.LOCAL_IMAGE, 'true')
}
Expand Down
39 changes: 38 additions & 1 deletion src/renderer/plugins/media-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { getAttachmentURL } from '@fe/services/base'
import { sleep } from '@fe/utils'
import type { Doc } from '@fe/types'

import 'viewerjs/dist/viewer.css'
import { isElectron } from '@fe/support/env'

function isMediaFile (doc?: Doc | null): 'video' | 'audio' | false {
Expand Down Expand Up @@ -87,5 +86,43 @@ export default {
},
component: MediaPlayer,
})

type XHTMLMediaElement = HTMLMediaElement & { _setAudioPreload?: (isInView: boolean) => void }

let observer: IntersectionObserver | null = null

function setAudioPreload (this: XHTMLMediaElement, isInView: boolean) {
if (isInView && this._setAudioPreload) {
this.preload = 'metadata'
delete this._setAudioPreload
observer?.unobserve(this)
}
}

function cleanObserver () {
observer?.disconnect()
observer = null
}

ctx.registerHook('VIEW_RENDERED', () => {
cleanObserver()

const medias = ctx.view.getViewDom()?.querySelectorAll<HTMLMediaElement>('audio')
if (medias && medias.length > 0) {
observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const el = entry.target as XHTMLMediaElement
el._setAudioPreload?.(entry.isIntersecting)
})
})

medias.forEach((media: XHTMLMediaElement) => {
if (media.preload === 'none') {
media._setAudioPreload = ctx.lib.lodash.debounce(setAudioPreload, 400, { leading: false, trailing: true })
observer!.observe(media)
}
})
}
})
}
} as Plugin
4 changes: 4 additions & 0 deletions src/renderer/services/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ export async function getContentHtml (options: BuildInHookTypes['VIEW_ON_GET_HTM
node.removeAttribute('target')
}

if (node.tagName === 'AUDIO') {
node.removeAttribute('preload')
}

const len = node.children.length
for (let i = len - 1; i >= 0; i--) {
const ele = node.children[i]
Expand Down

0 comments on commit 1b8b2e4

Please sign in to comment.