import browser from 'webextension-polyfill'; interface State { awaitingResponse: boolean feedUrl: string | null } const state: State = { awaitingResponse: false, feedUrl: null, } const getActiveTab = async () => { const [tab] = await browser.tabs.query({ active: true, currentWindow: true }) return tab } const onFeedDownloaded = (req: XMLHttpRequest) => { return async () => { state.awaitingResponse = false if (req.status >= 400) { console.error( `Could not load URL feed: ${req.responseURL}: ` + `${req.status}: ${req.statusText}` ) return } const tab = await getActiveTab() if (!tab || tab.id === -1) return await browser.tabs.sendMessage( tab.id, { type: 'renderFeed', url: req.responseURL, document: req.responseText } ) } } const downloadFeed = (url: string) => { state.awaitingResponse = true const req = new XMLHttpRequest() req.onload = onFeedDownloaded(req) req.open('GET', url) req.responseType = 'text' req.send() } const updateFeedUrl = (tabId: number, feedUrl: string | null) => { if (!feedUrl?.length) { browser.pageAction.hide() state.feedUrl = null } else { browser.pageAction.show(tabId) state.feedUrl = feedUrl } } browser.pageAction.onClicked.addListener( async () => { if (state.feedUrl?.length) downloadFeed(state.feedUrl) } ) browser.webNavigation.onCompleted.addListener( async (event: {tabId: number}) => { const { tabId } = event const feedUrl = await browser.tabs.sendMessage(tabId, {type: 'extractFeedUrl'}) await browser.tabs.sendMessage(tabId, {type: 'renderFeed', url: feedUrl}) updateFeedUrl(tabId, feedUrl) } ) browser.webRequest.onHeadersReceived.addListener( async (event: { url: string, responseHeaders: Array<{name: string, value: string}> }) => { if (state.awaitingResponse) return const {url, responseHeaders} = event const contentType = responseHeaders.find( h => h.name.toLowerCase() === 'content-type' )?.value || '' if ( contentType.startsWith('application/rss+xml') || contentType.startsWith('application/atom+xml') ) downloadFeed(url) }, {urls: ['']}, ['blocking', 'responseHeaders'] )