import { makeRemotelyCallable, remoteFunction } from 'webextension-rpc'; import { parseMediaFragmentIdentifier } from '../util/media-fragment-identifier'; const retrieveBookmarks = remoteFunction('retrieveBookmarks'); function fragmentIdentifierToSelector(fragmentIdentifier) { if (fragmentIdentifier.startsWith('#')) { fragmentIdentifier = fragmentIdentifier.substring(1); } const selector = { type: 'FragmentSelector', value: fragmentIdentifier, }; return selector; } function selectorToTime(selector) { if (selector.type !== 'FragmentSelector') { throw new Error(`Unsupported selector type: '${selector.type}'`); } const { start, end } = parseMediaFragmentIdentifier(selector.value); return { start, end }; } export default async function init(playlist) { const eventEmitter = playlist.getEventEmitter(); async function displayBookmarksInPage() { const bookmarks = await retrieveBookmarks({ url: document.URL }); const bookmarksWithTime = bookmarks.map(bookmark => { const fragmentIdentifier = bookmark.url.split('#')[1]; if (fragmentIdentifier === undefined) return null; const selector = fragmentIdentifierToSelector(fragmentIdentifier); try { const { start, end } = selectorToTime(selector); return { bookmark, start, end }; } catch (err) { // Likely a fragment identifier we do not understand; skip it. return null; } }).filter(value => value !== null); bookmarksWithTime.sort(({ start: t1 }, { start: t2 }) => t1 - t2); const annotations = bookmarksWithTime.map(({ bookmark, start, end }) => ({ start, end, id: bookmark.title, elementType: 'a', elementAttributes: { title: bookmark.title, href: bookmark.url, onclick: () => { eventEmitter.emit('select', start, end); }, }, })); playlist.setAnnotations({ annotations, annotationFormat: 'raw', editable: false }); playlist.drawRequest(); } makeRemotelyCallable({ displayBookmarksInPage, }); await displayBookmarksInPage(); }