From b5c10718ddeaa8fcac368515ca150705b1a2c5ab Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 29 Dec 2022 14:03:57 -0600 Subject: Refactor scripts, add table preview --- bridges/instagram.js | 10 --- bridges/twitter.js | 12 ---- bridges/youtube.js | 63 ------------------ content_scripts/bridges/instagram.js | 10 +++ content_scripts/bridges/twitter.js | 12 ++++ content_scripts/bridges/youtube.js | 63 ++++++++++++++++++ content_scripts/cs.js | 86 ++++++++++++++++++++++++ cs.js | 86 ------------------------ icon_128.png | Bin 1995 -> 0 bytes icon_default.png | Bin 3510 -> 0 bytes index.js | 62 ------------------ main.html | 16 ----- manifest.json | 18 ++--- options.html | 39 ----------- options.js | 23 ------- options/index.html | 39 +++++++++++ options/index.js | 23 +++++++ popup/index.js | 123 +++++++++++++++++++++++++++++++++++ popup/main.html | 22 +++++++ res/icon_128.png | Bin 0 -> 1995 bytes res/icon_default.png | Bin 0 -> 3510 bytes 21 files changed, 387 insertions(+), 320 deletions(-) delete mode 100644 bridges/instagram.js delete mode 100644 bridges/twitter.js delete mode 100644 bridges/youtube.js create mode 100644 content_scripts/bridges/instagram.js create mode 100644 content_scripts/bridges/twitter.js create mode 100644 content_scripts/bridges/youtube.js create mode 100644 content_scripts/cs.js delete mode 100644 cs.js delete mode 100644 icon_128.png delete mode 100644 icon_default.png delete mode 100644 index.js delete mode 100644 main.html delete mode 100644 options.html delete mode 100644 options.js create mode 100644 options/index.html create mode 100644 options/index.js create mode 100644 popup/index.js create mode 100644 popup/main.html create mode 100644 res/icon_128.png create mode 100644 res/icon_default.png diff --git a/bridges/instagram.js b/bridges/instagram.js deleted file mode 100644 index 0ced06a..0000000 --- a/bridges/instagram.js +++ /dev/null @@ -1,10 +0,0 @@ -async function get_insta() { - let url = window.location.href; - let insta_url = url + "?__a=1" - let res = await fetch(insta_url); - let json = await res.json(); - let uid = json.graphql.user.id - let feed_url = `${base_url}/?action=display&bridge=Instagram&context=Username&u=${uid}&media_type=all&format=`; - return get_all_types(feed_url) -} - diff --git a/bridges/twitter.js b/bridges/twitter.js deleted file mode 100644 index e9855cb..0000000 --- a/bridges/twitter.js +++ /dev/null @@ -1,12 +0,0 @@ -function get_twitter() { - let url = window.location.href; - let pattern = /twitter.com\/(\w+).*/ - 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) - } - return [] -} - diff --git a/bridges/youtube.js b/bridges/youtube.js deleted file mode 100644 index 202873b..0000000 --- a/bridges/youtube.js +++ /dev/null @@ -1,63 +0,0 @@ -function get_native_playlist_feed(playlistId){ - return `https://www.youtube.com/feeds/videos.xml?playlist_id=${playlistId}` -} - -function get_native_channel_feed(channelId){ - return `https://www.youtube.com/feeds/videos.xml?channel_id=${channelId}` -} - -async function get_youtube() { - let url = window.location.href; - - let patternVideo = /youtube.com\/watch\?v=[A-z0-9-_]+/ - let matchVideo = url.match(patternVideo) - - let patternUser = /youtube.com\/user\/[A-z0-9-_]+.*/ - let matchUser = url.match(patternUser) - - let patternChannel = /youtube.com\/channel\/[A-z0-9-_]+.*/ - let matchChannel = url.match(patternChannel) - - let patternPlaylist = /youtube.com\/playlist\?list=[A-z0-9-_]+.*/ - let matchPlaylist = url.match(patternPlaylist) - - if (matchVideo) { - let channel_url = document.querySelector("[role='main'] #channel-name a")["href"] - let matchChannel2 = channel_url.match(patternChannel) - let channelId = matchChannel2[1] - let feed_url = `${base_url}/?action=display&bridge=Youtube&context=By+channel+id&c=${channelId}&duration_min=&duration_max=&format=` - let native_url = get_native_channel_feed(channelId) - let feeds = get_all_types(feed_url, "channel").concat([{ type: `native (channel): Rss`, url: native_url }]) - - let patternListInVideo = /youtube.com\/watch\?v=\w+\&list=(\w+)/ - let matchListInVideo = url.match(patternListInVideo) - if(matchListInVideo){ - 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) - let rb_feeds = get_all_types(playlist_feed_url, "playlist") - feeds = feeds.concat(rb_feeds.concat([{ type: `native (playlist): Rss`, url: native_url }])) - } - - return feeds - } - if (matchUser) { - 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) { - 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) { - 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=` - let rb_feeds = get_all_types(feed_url) - return rb_feeds.concat([{ type: `native: Rss`, url: native_url }]) - } - return [] -} - diff --git a/content_scripts/bridges/instagram.js b/content_scripts/bridges/instagram.js new file mode 100644 index 0000000..0ced06a --- /dev/null +++ b/content_scripts/bridges/instagram.js @@ -0,0 +1,10 @@ +async function get_insta() { + let url = window.location.href; + let insta_url = url + "?__a=1" + let res = await fetch(insta_url); + let json = await res.json(); + let uid = json.graphql.user.id + let feed_url = `${base_url}/?action=display&bridge=Instagram&context=Username&u=${uid}&media_type=all&format=`; + return get_all_types(feed_url) +} + diff --git a/content_scripts/bridges/twitter.js b/content_scripts/bridges/twitter.js new file mode 100644 index 0000000..e9855cb --- /dev/null +++ b/content_scripts/bridges/twitter.js @@ -0,0 +1,12 @@ +function get_twitter() { + let url = window.location.href; + let pattern = /twitter.com\/(\w+).*/ + 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) + } + return [] +} + diff --git a/content_scripts/bridges/youtube.js b/content_scripts/bridges/youtube.js new file mode 100644 index 0000000..202873b --- /dev/null +++ b/content_scripts/bridges/youtube.js @@ -0,0 +1,63 @@ +function get_native_playlist_feed(playlistId){ + return `https://www.youtube.com/feeds/videos.xml?playlist_id=${playlistId}` +} + +function get_native_channel_feed(channelId){ + return `https://www.youtube.com/feeds/videos.xml?channel_id=${channelId}` +} + +async function get_youtube() { + let url = window.location.href; + + let patternVideo = /youtube.com\/watch\?v=[A-z0-9-_]+/ + let matchVideo = url.match(patternVideo) + + let patternUser = /youtube.com\/user\/[A-z0-9-_]+.*/ + let matchUser = url.match(patternUser) + + let patternChannel = /youtube.com\/channel\/[A-z0-9-_]+.*/ + let matchChannel = url.match(patternChannel) + + let patternPlaylist = /youtube.com\/playlist\?list=[A-z0-9-_]+.*/ + let matchPlaylist = url.match(patternPlaylist) + + if (matchVideo) { + let channel_url = document.querySelector("[role='main'] #channel-name a")["href"] + let matchChannel2 = channel_url.match(patternChannel) + let channelId = matchChannel2[1] + let feed_url = `${base_url}/?action=display&bridge=Youtube&context=By+channel+id&c=${channelId}&duration_min=&duration_max=&format=` + let native_url = get_native_channel_feed(channelId) + let feeds = get_all_types(feed_url, "channel").concat([{ type: `native (channel): Rss`, url: native_url }]) + + let patternListInVideo = /youtube.com\/watch\?v=\w+\&list=(\w+)/ + let matchListInVideo = url.match(patternListInVideo) + if(matchListInVideo){ + 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) + let rb_feeds = get_all_types(playlist_feed_url, "playlist") + feeds = feeds.concat(rb_feeds.concat([{ type: `native (playlist): Rss`, url: native_url }])) + } + + return feeds + } + if (matchUser) { + 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) { + 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) { + 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=` + let rb_feeds = get_all_types(feed_url) + return rb_feeds.concat([{ type: `native: Rss`, url: native_url }]) + } + return [] +} + diff --git a/content_scripts/cs.js b/content_scripts/cs.js new file mode 100644 index 0000000..e57176b --- /dev/null +++ b/content_scripts/cs.js @@ -0,0 +1,86 @@ +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 = [] + +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() + all_feed_urls = all_feed_urls.concat(result) + break + } + } + } + all_feed_urls = all_feed_urls.concat(find_links_in_page()) + return all_feed_urls +} + +function register(hosts, callback) { + objs.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/cs.js b/cs.js deleted file mode 100644 index e57176b..0000000 --- a/cs.js +++ /dev/null @@ -1,86 +0,0 @@ -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 = [] - -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() - all_feed_urls = all_feed_urls.concat(result) - break - } - } - } - all_feed_urls = all_feed_urls.concat(find_links_in_page()) - return all_feed_urls -} - -function register(hosts, callback) { - objs.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/icon_128.png b/icon_128.png deleted file mode 100644 index a3e973d..0000000 Binary files a/icon_128.png and /dev/null differ diff --git a/icon_default.png b/icon_default.png deleted file mode 100644 index 75ca555..0000000 Binary files a/icon_default.png and /dev/null differ diff --git a/index.js b/index.js deleted file mode 100644 index 86220b9..0000000 --- a/index.js +++ /dev/null @@ -1,62 +0,0 @@ - -var base_reader = undefined - -function subscribe_link(reader, feed_url){ - if(reader == "ttrss"){ - return `${base_reader}/public.php?op=subscribe&feed_url=${encodeURIComponent(feed_url)}`; - } else { - return `${base_reader}/bookmarklet?uri=${encodeURIComponent(feed_url)}`; - } -} - -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..." - browser.tabs.query({ active: true, currentWindow: true }, function (tabs) { - browser.tabs.sendMessage(tabs[0].id, {}).then( - function (feed_urls) { - feeds.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); - - let newP = document.createElement('p') - newP.innerText = `Found ${feed_urls.length} feeds` - feeds.append(newP) - return; - } - - feed_urls.forEach(item => { - let newLink = document.createElement('a'); - newLink["href"] = item.url - newLink.innerText = item.type; - - - let newDiv = document.createElement('div'); - newDiv.append(newLink) - - if(base_reader){ - let subLink = document.createElement('a'); - subLink["href"] = subscribe_link(settings.reader, item.url) - subLink.innerText = "subscribe"; - newDiv.append(subLink) - } - - feeds.append(newDiv) - }) - if(feed_urls.length == 0) { - let newP = document.createElement('p') - newP.innerText = "No feeds found" - feeds.append(newP) - } - }); - }); -} - diff --git a/main.html b/main.html deleted file mode 100644 index 1895055..0000000 --- a/main.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - -

RSS Feeds

-
- - - diff --git a/manifest.json b/manifest.json index 0fa1dea..a98c9d8 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "description": "Finds feeds or generates RSS-Bridge URLs for the current page. Optional integration with tt-rss.", "manifest_version": 2, "name": "RSS-Bridge helper", - "version": "1.2", + "version": "1.3", "content_scripts": [ { "matches": [ @@ -10,17 +10,17 @@ "https://*/*" ], "js": [ - "bridges/youtube.js", - "bridges/twitter.js", - "bridges/instagram.js", - "cs.js" + "content_scripts/bridges/youtube.js", + "content_scripts/bridges/twitter.js", + "content_scripts/bridges/instagram.js", + "content_scripts/cs.js" ] } ], "browser_action": { - "default_icon": "icon_default.png", + "default_icon": "res/icon_default.png", "default_title": "See feeds for this page", - "default_popup": "main.html" + "default_popup": "popup/main.html" }, "permissions": [ "http://*/*", @@ -29,7 +29,7 @@ "tabs" ], "options_ui": { - "page": "options.html" + "page": "options/index.html" }, "browser_specific_settings": { "gecko": { @@ -38,6 +38,6 @@ } }, "icons": { - "128": "icon_128.png" + "128": "res/icon_128.png" } } diff --git a/options.html b/options.html deleted file mode 100644 index 5677612..0000000 --- a/options.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - Options - - - -
- - - - - - - - - - - - - - - - -
- -
- -
-
- - - - diff --git a/options.js b/options.js deleted file mode 100644 index 3d85dbe..0000000 --- a/options.js +++ /dev/null @@ -1,23 +0,0 @@ -function saveOptions(e) { - e.preventDefault(); - browser.storage.sync.set({ - rb: document.querySelector("#rb").value, - reader: document.querySelector("#reader").value, - instance: document.querySelector("#instance").value - }); -} -function restoreOptions() { - function setCurrentChoice(result) { - document.querySelector("#rb").value = result.rb || ""; - document.querySelector("#reader").value = result.reader|| ""; - document.querySelector("#instance").value = result.instance || ""; - } - function onError(error) { - console.log(`Error: ${error}`); - } - let getting = browser.storage.sync.get(["rb", "instance", "reader"]); - getting.then(setCurrentChoice, onError); -} -document.addEventListener("DOMContentLoaded", restoreOptions); -document.querySelector("form").addEventListener("submit", saveOptions); - diff --git a/options/index.html b/options/index.html new file mode 100644 index 0000000..9817b71 --- /dev/null +++ b/options/index.html @@ -0,0 +1,39 @@ + + + + + + Options + + + +
+ + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + + + diff --git a/options/index.js b/options/index.js new file mode 100644 index 0000000..3d85dbe --- /dev/null +++ b/options/index.js @@ -0,0 +1,23 @@ +function saveOptions(e) { + e.preventDefault(); + browser.storage.sync.set({ + rb: document.querySelector("#rb").value, + reader: document.querySelector("#reader").value, + instance: document.querySelector("#instance").value + }); +} +function restoreOptions() { + function setCurrentChoice(result) { + document.querySelector("#rb").value = result.rb || ""; + document.querySelector("#reader").value = result.reader|| ""; + document.querySelector("#instance").value = result.instance || ""; + } + function onError(error) { + console.log(`Error: ${error}`); + } + let getting = browser.storage.sync.get(["rb", "instance", "reader"]); + getting.then(setCurrentChoice, onError); +} +document.addEventListener("DOMContentLoaded", restoreOptions); +document.querySelector("form").addEventListener("submit", saveOptions); + diff --git a/popup/index.js b/popup/index.js new file mode 100644 index 0000000..c674f39 --- /dev/null +++ b/popup/index.js @@ -0,0 +1,123 @@ +var base_reader = undefined + +function subscribe_link(reader, feed_url){ + if(reader == "ttrss"){ + return `${base_reader}/public.php?op=subscribe&feed_url=${encodeURIComponent(feed_url)}`; + } else { + return `${base_reader}/bookmarklet?uri=${encodeURIComponent(feed_url)}`; + } +} + +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..." + browser.tabs.query({ active: true, currentWindow: true }, function (tabs) { + browser.tabs.sendMessage(tabs[0].id, {}).then( + function (feed_urls) { + feeds.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); + + let newP = document.createElement('p') + newP.innerText = `Found ${feed_urls.length} feeds` + feeds.append(newP) + return; + } + + feed_urls.forEach(item => { + let newLink = document.createElement('a'); + newLink["href"] = item.url + newLink.innerText = item.type; + + + let newDiv = document.createElement('div'); + newDiv.append(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["href"] = "#" + previewLink.innerText = "preview"; + newDiv.append(previewLink) + + if(base_reader){ + let subLink = document.createElement('a'); + subLink["href"] = subscribe_link(settings.reader, item.url) + subLink.innerText = "subscribe"; + newDiv.append(subLink) + } + + feeds.append(newDiv) + }) + if(feed_urls.length == 0) { + let newP = document.createElement('p') + newP.innerText = "No feeds found" + feeds.append(newP) + } + }); + }); +} + diff --git a/popup/main.html b/popup/main.html new file mode 100644 index 0000000..81f8f06 --- /dev/null +++ b/popup/main.html @@ -0,0 +1,22 @@ + + + + + + + +

RSS Feeds

+
+ + + diff --git a/res/icon_128.png b/res/icon_128.png new file mode 100644 index 0000000..a3e973d Binary files /dev/null and b/res/icon_128.png differ diff --git a/res/icon_default.png b/res/icon_default.png new file mode 100644 index 0000000..75ca555 Binary files /dev/null and b/res/icon_default.png differ -- cgit v1.2.3