From 3bdc11a9b2c78f2be8c11d28befce7328b6e5424 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 30 Dec 2022 13:58:20 -0600 Subject: Improve RSS preview --- content_scripts/bridges/instagram.js | 2 +- content_scripts/bridges/twitter.js | 10 +- content_scripts/bridges/youtube.js | 9 +- content_scripts/cs.js | 75 ++------------ content_scripts/rss_bridge.js | 20 ++++ content_scripts/scraper.js | 35 +++++++ manifest.json | 6 +- popup/index.js | 191 +++++++++++++++++++++-------------- popup/main.html | 7 +- 9 files changed, 200 insertions(+), 155 deletions(-) create mode 100644 content_scripts/rss_bridge.js create mode 100644 content_scripts/scraper.js diff --git a/content_scripts/bridges/instagram.js b/content_scripts/bridges/instagram.js index 0ced06a..18988b9 100644 --- a/content_scripts/bridges/instagram.js +++ b/content_scripts/bridges/instagram.js @@ -7,4 +7,4 @@ async function get_insta() { let feed_url = `${base_url}/?action=display&bridge=Instagram&context=Username&u=${uid}&media_type=all&format=`; return get_all_types(feed_url) } - +register(["instagram"], get_insta) diff --git a/content_scripts/bridges/twitter.js b/content_scripts/bridges/twitter.js index e9855cb..1ffa131 100644 --- a/content_scripts/bridges/twitter.js +++ b/content_scripts/bridges/twitter.js @@ -4,9 +4,15 @@ function get_twitter() { let match = url.match(pattern); if (match) { let twitter_handle = match[1] + let feed_url = `${base_url}/?action=display&bridge=Twitter&context=By+username&u=${twitter_handle}&format=` - return get_all_types(feed_url) + let feeds = get_all_types(feed_url) + + let feed_url_norep = `${base_url}/?action=display&bridge=Twitter&context=By+username&u=${twitter_handle}&norep=on&format=` + let feeds_norep = get_all_types(feed_url, "no replies") + + return feeds.concat(feeds_norep) } return [] } - +register(["twitter"], get_twitter) diff --git a/content_scripts/bridges/youtube.js b/content_scripts/bridges/youtube.js index 202873b..e6b584c 100644 --- a/content_scripts/bridges/youtube.js +++ b/content_scripts/bridges/youtube.js @@ -31,7 +31,7 @@ async function get_youtube() { let patternListInVideo = /youtube.com\/watch\?v=\w+\&list=(\w+)/ let matchListInVideo = url.match(patternListInVideo) - if(matchListInVideo){ + if(matchListInVideo && matchListInVideo[1]){ let playlistId = matchListInVideo[1] let playlist_feed_url = `${base_url}/?action=display&bridge=Youtube&context=By+playlist+Id&p=${playlistId}&duration_min=&duration_max=&format=` let native_url = get_native_playlist_feed(playlistId) @@ -41,17 +41,17 @@ async function get_youtube() { return feeds } - if (matchUser) { + if (matchUser && matchUser[1]) { let user = matchUser[1]; let feed_url = `${base_url}/?action=display&bridge=Youtube&context=By+username&u=${user}&duration_min=&duration_max=&format=` return get_all_types(feed_url) } - if (matchChannel) { + if (matchChannel && matchChannel[1]) { let channelId = matchChannel[1] let feed_url = `${base_url}/?action=display&bridge=Youtube&context=By+channel+id&c=${channelId}&duration_min=&duration_max=&format=` return get_all_types(feed_url) } - if (matchPlaylist) { + if (matchPlaylist && matchPlaylist[1]) { let playlistId = matchPlaylist[1] let native_url = get_native_playlist_feed(playlistId) let feed_url = `${base_url}/?action=display&bridge=Youtube&context=By+playlist+Id&p=${playlistId}&duration_min=&duration_max=&format=` @@ -61,3 +61,4 @@ async function get_youtube() { return [] } +register(["youtube"], get_youtube) diff --git a/content_scripts/cs.js b/content_scripts/cs.js index e57176b..6b66d92 100644 --- a/content_scripts/cs.js +++ b/content_scripts/cs.js @@ -1,86 +1,29 @@ var base_url = undefined -let formats = ["Atom", "Mrss", "Html"] -let types = { - 'application/rss+xml': "rss", - 'application/atom+xml': "atom", - 'application/rdf+xml': "rdf", - 'application/rss': "rss", - 'application/atom': "atom", - 'application/rdf': "rdf", - 'text/rss+xml': "rss", - 'text/atom+xml': "atom", - 'text/rdf+xml': "rdf", - 'text/rss': "rss", - 'text/atom': "atom", - 'text/rdf': "rdf" -} - - -function find_links_in_page() { - let links = document.querySelectorAll('link[type]'); - let feeds = []; - for (let i = 0; i < links.length; i++) { - if (links[i].hasAttribute('type') && links[i].getAttribute('type') in types) { - let title = links[i].getAttribute('title') - let href = links[i].getAttribute('href') - let feed_url = new URL(href, window.location.href).href - let type = types[links[i].getAttribute('type')] - let feed = { - type: `native: ${title || type}`, - url: feed_url, - }; - feeds.push(feed); - } - } - return feeds -} - -function get_all_types(feed_url, note) { - let feeds = []; - formats.forEach(el => { - if(note){ - feeds.push({ - type: `rss-bridge (${note}): ${el}`, - url: feed_url + el - }); - } else { - feeds.push({ - type: `rss-bridge: ${el}`, - url: feed_url + el - }); - } - }) - return feeds; -} - -let objs = [] +// Get the list of all feeds, combining bridged and native feeds async function get_feed_urls() { let settings = await browser.storage.sync.get("rb"); base_url = settings.rb; let all_feed_urls = [] - let host = window.location.host; - for (const obj of objs) { - for (const obj_host of obj.hosts) { - if (host.includes(obj_host)) { - result = await obj.callback() + for (const bridge of bridges) { + for (const host of bridge.hosts) { + if (window.location.host.includes(host)) { + result = await bridge.callback() all_feed_urls = all_feed_urls.concat(result) break } } } - all_feed_urls = all_feed_urls.concat(find_links_in_page()) + all_feed_urls = all_feed_urls.concat(find_feeds_in_page()) return all_feed_urls } +// Function to register a new bridge +let bridges = [] function register(hosts, callback) { - objs.push({hosts, callback}) + bridges.push({hosts, callback}) } -register(["instagram"], get_insta) -register(["twitter"], get_twitter) -register(["youtube"], get_youtube) - browser.runtime.onMessage.addListener(function (msg, sender) { return Promise.resolve(get_feed_urls()); }) diff --git a/content_scripts/rss_bridge.js b/content_scripts/rss_bridge.js new file mode 100644 index 0000000..ac591bd --- /dev/null +++ b/content_scripts/rss_bridge.js @@ -0,0 +1,20 @@ +let formats = ["Atom", "Mrss"] +function get_all_types(feed_url, note) { + let feeds = []; + formats.forEach(el => { + if(note){ + feeds.push({ + type: el, + name: `rss-bridge (${note}): ${el}`, + url: feed_url + el + }); + } else { + feeds.push({ + type: el, + name: `rss-bridge: ${el}`, + url: feed_url + el + }); + } + }) + return feeds; +} diff --git a/content_scripts/scraper.js b/content_scripts/scraper.js new file mode 100644 index 0000000..51043c3 --- /dev/null +++ b/content_scripts/scraper.js @@ -0,0 +1,35 @@ +let types = { + 'application/rss+xml': "rss", + 'application/atom+xml': "atom", + 'application/rdf+xml': "rdf", + 'application/rss': "rss", + 'application/atom': "atom", + 'application/rdf': "rdf", + 'text/rss+xml': "rss", + 'text/atom+xml': "atom", + 'text/rdf+xml': "rdf", + 'text/rss': "rss", + 'text/atom': "atom", + 'text/rdf': "rdf" +} + +// Scrape feed links from DOM +function find_feeds_in_page() { + let links = document.querySelectorAll('link[type]'); + let feeds = []; + for (let i = 0; i < links.length; i++) { + if (links[i].hasAttribute('type') && links[i].getAttribute('type') in types) { + let title = links[i].getAttribute('title') + let href = links[i].getAttribute('href') + let feed_url = new URL(href, window.location.href).href + let type = types[links[i].getAttribute('type')] + let feed = { + name: `native: ${title || type}`, + type: type, + url: feed_url, + }; + feeds.push(feed); + } + } + return feeds +} diff --git a/manifest.json b/manifest.json index a98c9d8..0e84d52 100644 --- a/manifest.json +++ b/manifest.json @@ -10,10 +10,12 @@ "https://*/*" ], "js": [ + "content_scripts/cs.js", + "content_scripts/rss_bridge.js", + "content_scripts/scraper.js", "content_scripts/bridges/youtube.js", "content_scripts/bridges/twitter.js", - "content_scripts/bridges/instagram.js", - "content_scripts/cs.js" + "content_scripts/bridges/instagram.js" ] } ], diff --git a/popup/index.js b/popup/index.js index c674f39..4944e9f 100644 --- a/popup/index.js +++ b/popup/index.js @@ -8,114 +8,149 @@ function subscribe_link(reader, feed_url){ } } +function insertElementsIntoRow(rowElement, elements){ + let tdElement = document.createElement("td") + elements.forEach( el => tdElement.append(el)) + rowElement.append(tdElement) +} + +function insertElementIntoRow(rowElement, element){ + let tdElement = document.createElement("td") + tdElement.append(element) + rowElement.append(tdElement) +} + +function wrapInDiv(element){ + let wrapperDiv = document.createElement("div") + wrapperDiv.append(element) + return wrapperDiv +} + +let itemMap = { + "updated": "pubDate", + "summary": "description", +} +function parseCollection(collection, entries){ + for(const child of collection){ + feedEntry = {"link": "", "title": "", "pubDate": "", "description": ""} + for(const c of child.children){ + if(c.tagName == "link" && c.getAttribute("href")){ + feedEntry["link"] = c.getAttribute("href") + } else { + feedEntry[c.tagName] = c.innerHTML + } + } + // Copy keys to normalized version + for(const key in itemMap){ + if(feedEntry[key]){ + feedEntry[itemMap[key]] = feedEntry[key] + } + } + entries.push(feedEntry) + } +} + +function previewOnclick(item){ + return function(){ + fetch(item.url) + .then( r => r.text() ) + .then(r => new window.DOMParser().parseFromString(r, "text/xml")) + .then(p => { + let entries = [] + parseCollection(p.getElementsByTagName("entry"), entries) + parseCollection(p.getElementsByTagName("item"), entries) + + let tableEl = document.createElement("table") + tableEl.classList.add("preview") + entries.forEach(entry => { + let trEl = document.createElement("tr") + tableEl.append(trEl) + + let titleEl = document.createElement("a") + titleEl.href = entry["link"] + titleEl.innerHTML = entry["title"] + + let wrapperDiv2 = document.createElement("div") + wrapperDiv2.innerText = entry["pubDate"] + + insertElementsIntoRow(trEl, [ + wrapInDiv(titleEl), wrapperDiv2 + ]) + + let td3El = document.createElement("td") + td3El.innerHTML = entry["description"] + trEl.append(td3El) + }) + feeds.append(tableEl) + }) + } +} + window.onload = async function () { let settings = await browser.storage.sync.get(["rb", "reader", "instance"]); base_reader = settings.instance; let base_rb = settings.rb; - let feeds = document.getElementById('feeds'); - feeds.innerText = "Loading..." + let feedsElement = document.getElementById('feeds'); + feedsElement.innerText = "Loading..." browser.tabs.query({ active: true, currentWindow: true }, function (tabs) { browser.tabs.sendMessage(tabs[0].id, {}).then( - function (feed_urls) { - feeds.innerText = "" + function (feeds) { + feedsElement.innerText = "" if(!base_rb) { let newSettingsLink = document.createElement("a") newSettingsLink["href"] = "/options.html" newSettingsLink.innerText = "RSS-bridge instance not set! Click here to open options."; let newDiv = document.createElement('div'); newDiv.append(newSettingsLink); - feeds.appendChild(newDiv); + feedsElement.appendChild(newDiv); let newP = document.createElement('p') - newP.innerText = `Found ${feed_urls.length} feeds` - feeds.append(newP) + newP.innerText = `Found ${feeds.length} feeds` + feedsElement.append(newP) return; } - feed_urls.forEach(item => { - let newLink = document.createElement('a'); - newLink["href"] = item.url - newLink.innerText = item.type; - + let table = document.createElement("table") + table.classList.add("feeds") + feedsElement.append(table) + feeds.forEach(feed => { + let newRow = document.createElement("tr") + table.append(newRow) - let newDiv = document.createElement('div'); - newDiv.append(newLink) + let newLink = document.createElement('a'); + newLink["href"] = feed.url + newLink.innerText = feed.name; + insertElementIntoRow(newRow, newLink) let previewLink = document.createElement('a'); - previewLink["onclick"] = function(){ - fetch(item.url) - .then( r => r.text() ) - .then(r => new window.DOMParser().parseFromString(r, "text/xml")) - .then(p => { - let channelTitle = "Items" - let description = undefined - let items = [] - let lastBuild = undefined - console.log(p.firstChild.children) - for(const channel of p.firstChild.children) { - //p.firstChild.children.forEach(channel => { - for(const child of channel.children) { - //channel.children.forEach(child => { - if(child.tagName == "title"){ - channelTitle = child.textContent - } else if (child.tagName == "lastBuildDate") { - lastBuild = child.textContent - } else if (child.tagName == "description") { - description = child.textContent - } else if (child.tagName == "item") { - item = {} - for(const c of child.children){ - //child.children.forEach(c => { - item[c.tagName] = c.innerHTML - } - items.push(item) - } - } - } - console.log(items) - let tableEl = document.createElement("table") - items.forEach(item => { - let trEl = document.createElement("tr") - tableEl.append(trEl) - - let tdEl = document.createElement("td") - - let titleEl = document.createElement("a") - titleEl.href = item["link"] - titleEl.innerText = item["title"] - let wrapperDiv = document.createElement("div") - wrapperDiv.append(titleEl) - let wrapperDiv2 = document.createElement("div") - wrapperDiv2.innerText = item["pubDate"] - tdEl.append(wrapperDiv) - tdEl.append(wrapperDiv2) - trEl.append(tdEl) - - let td3El = document.createElement("td") - td3El.innerHTML = item["description"] - trEl.append(td3El) - - }) - feeds.append(tableEl) - }) - } + previewLink["onclick"] = previewOnclick(feed) previewLink["href"] = "#" previewLink.innerText = "preview"; - newDiv.append(previewLink) + + let newPreviewData = document.createElement("td") + // Preview only works for XML feeds + if( + feed.type.toLowerCase().includes("rss") || + feed.type.toLowerCase().includes("xml") || + feed.type.toLowerCase().includes("atom") + ){ + newPreviewData.append(previewLink) + } + newRow.append(newPreviewData) if(base_reader){ let subLink = document.createElement('a'); - subLink["href"] = subscribe_link(settings.reader, item.url) + subLink["href"] = subscribe_link(settings.reader, feed.url) subLink.innerText = "subscribe"; - newDiv.append(subLink) + let newSubData = document.createElement("td") + newSubData.append(subLink) + newRow.append(newSubData) } - - feeds.append(newDiv) }) - if(feed_urls.length == 0) { + if(feeds.length == 0) { let newP = document.createElement('p') newP.innerText = "No feeds found" - feeds.append(newP) + feedsElement.append(newP) } }); }); diff --git a/popup/main.html b/popup/main.html index 81f8f06..6c57d10 100644 --- a/popup/main.html +++ b/popup/main.html @@ -6,12 +6,15 @@ div a { margin: 1em; } - table td a { + table.preview td a { margin: 0em; } - td { + table.preview td { border: 1px solid black; } + table.feeds tr td { + //border-bottom: 1px solid black; + } -- cgit v1.2.3