106 lines
2.3 KiB
TypeScript
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']
|
|
)
|
|
|