rss-viewer-browser-extension/src/background.ts

106 lines
2.3 KiB
TypeScript

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: ['<all_urls>']},
['blocking', 'responseHeaders']
)