Reeywhaar / want-my-rss

RSS features for Firefox
Other
113 stars 10 forks source link

support for domains that don't advertise feeds (without feed detection) #16

Open atomGit opened 5 years ago

atomGit commented 5 years ago

wow, this is a very nice extension! but (and there's always a "but", tight?) it doesn't support feeds for some very popular websites, such as YouTube, BitChute, Vimeo

feeds for all of these platforms can be built statically by reformatting the URL - please see...

How to access RSS feeds for websites that don’t advertise one

Reeywhaar commented 5 years ago

Thanks for suggestion!

I've tried Youtube Feeds from the article you mentioned, and it seems to work fine with extension. There red icon appears in url bar and on click my extension's show page opens (thought I see a bug, once in ten times standard page appears :/ ).

As for supporting these popular websites, I think it's very unrewarding and time consuming pastime. Something will be always broken, because I can't put my eyes on every website. This is sad state of the web where big corporations decide to lock in their users and not contribute to open data standards.

I think external extension can be made. Everything needed is to append <link rel="alternate" type="{feed type}" title="{feed title}" href="{feed src}" /> to the head tag on the site from a list, my extension then do the job. But there must be a group of enthusiasts which will take care of their personal part of websites which they visit often.

atomGit commented 5 years ago

I think external extension can be made. Everything needed is to append ...

what about adding a custom URL format option where users could add their own rules (using variables) to pick up these feeds? i think that might be a great way to go whilst not requiring a lot of additional coding on your part maybe ???

so WMR segments the URL and assigns variables to the parts which allow the user to create a feed URL - example...

https://www.youtube.com/channel/UCs84giQmEVI8NXXg78Fvk2g

WMR does this...

https://www.youtube.com/{part-a}/{part-b}

user then creates the feed URL...

feeds/videos.xml?channel_id={part-b}

which WMR uses to load the full URL...

https://www.youtube.com/feeds/videos.xml?channel_id=UCs84giQmEVI8NXXg78Fvk2g

Reeywhaar commented 5 years ago

Such things can't be done with some predefined blocks, and require basic coding skills.

If you really need you are already able to install Tampermonkey or some userscript extension, somehow obtain feed link and append it to head. For youtube you can use Youtube Feeds :-)

atomGit commented 5 years ago

thanks for the explanation

Reeywhaar commented 5 years ago

Not that I'm completely against, need to think about it. It just not that easy peasy :-)

atomGit commented 5 years ago

understood - my reason for the request is to have a single-add-on that handles all feeds (to the extent that's doable) - i don't like installing more than i have to :)

atomGit commented 5 years ago

sorry, don't mean to be a PITA and maybe this is useless, but i had another thought...

wadif somebody somewhere (mainly you, here :heart: ) kept a simple redirect "rules" file that other's can contrib to in order to lighten your load so WMR doesn't have to do any fancy url parsing shenanigans internally - example rules/redirect file:

www.youtube.com/channel/([a-z0-9]+) www.youtube.com/feeds/videos.xml?channel_id=$1

so WMR reads the rules file and thus recognizes when www.youtube.com/channel/ is loaded, process the RegEx strictly according to the rules file, then displays its icon, ready for the user to click

no new permissions needed i think? and no messing with url's - just have to add code to process the expressions maybe and add the result(s) to whatever WMR normally finds, if anything

i'll stop bothering you now :)

Reeywhaar commented 5 years ago

I'm thinking basic rewrite rules will not last, as sometimes feed link consists not only of original url parts, and if I'll add such solution, eventually I'll have to change this rules option, thus, break backward compatibility, so, this is why I don't like this approach.

atomGit commented 12 months ago

there was an excellent add-on i was using to detect feeds that is no longer available and so i'd like to re-address this issue

I'm thinking basic rewrite rules will not last, as sometimes feed link consists not only of original url parts, and if I'll add such solution, eventually I'll have to change this rules option, ...

i've not ever seen that happen in quite a few years for any site which provides feeds, but doesn't advertise them

How to access RSS feeds for websites that don't advertise one - 12bytes.org

here's the code the other dev was using to detect feeds - he made a default file available on his github repo, but the user could add/remove/edit the code right from the extension

code ```js ^https:\/\/.* (() => { const feeds = []; let tmp; const url = new URL(window.location.href); for (let link_href of [ ...new Set( Array.from(document.querySelectorAll("link")).map((l) => l.getAttribute("href") ) ), ]) { if (typeof link_href === "string") { link_href = link_href.trim(); // relativ href if (!link_href.startsWith("http") && !link_href.startsWith("//")) { try { tmp = new URL(link_href, url.origin + url.pathname); if (tmp !== null) { link_href = tmp.toString(); } } catch (e) { console.warn("failed to built a valid absolute url for", link_href); } } feeds.push(link_href); } } [ "/feed/rss2", "/feed/rss", "/feed", "/rss", "/rss.xml", "/feed.xml", "/?feed=rss2", "/?feed=rss", "/?feed=atom", ].forEach((e) => { tmp = new URL(e, url.origin); tmp = tmp.toString(); feeds.push(tmp); tmp = new URL(e, url.origin + url.pathname); tmp = tmp.toString(); feeds.push(tmp); }); return feeds; })(); --- ^https:\/\/www\.youtube\.com\/.* (() => { function getYTFeeds(url) { const feedbase = "https://www.youtube.com/feeds/videos.xml?"; const feeds = []; let tmp; url = new URL(url); const pathnameParts = url.pathname.split("/"); if (pathnameParts.length > 1) { switch (pathnameParts[1]) { case "user": if (pathnameParts.length > 2) { feeds.push(feedbase + "user=" + pathnameParts[2]); } break; case "channel": if (pathnameParts.length > 2) { feeds.push(feedbase + "channel_id=" + pathnameParts[2]); } break; case "playlist": tmp = url.searchParams.get("list"); if (typeof tmp === "string" && tmp.length > 0) { feeds.push(feedbase + "playlist_id=" + tmp); } break; case "watch": for (const e of [ ".ytp-ce-channel-title.ytp-ce-link", // New layout (faster - test) "yt-formatted-string#owner-name :first-child", // New layout ".yt-user-info :first-child", // Old layout ]) { tmp = document.querySelector(e); if (tmp && typeof tmp.href === "string") { feeds = feeds.concat(getYTFeed(tmp.href)); } } break; } } return feeds; } return getYTFeeds(window.location.href); })(); --- ^https:\/\/((math|softwareengineering|electronics|security|scifi|apple|skeptics|crypto|movies|mathematica|anime|networkengineering|softwarerecs|worldbuilding|meta)\.stackexchange|stackoverflow|serverfault|askubuntu|mathoverflow)\.(com|net)/.* (() => { const feeds = []; const url = new URL(window.location.href); const parts = url.pathname.split("/"); for (const tmp of [ "feeds", "feeds/featured", "feeds/hot", "feeds/week", "feeds/month", ]) { feeds.push(url.origin + "/" + tmp); } if (parts.length > 1) { switch (parts[1]) { case "question": const question_id = parts[2]; feeds.push(url.origin + "/feeds/question/" + question_id); break; case "users": const user_id = parts[2]; feeds.push(url.origin + "/feeds/user/" + user_id); feeds.push(url.origin + "/feeds/user/" + user_id + "/responses"); break; } } return feeds; })(); --- ^https:\/\/(hive\.blog)|(steemit\.com)\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); const parts = url.pathname.split("/"); if (parts.length > 1) { if (parts[1][0] === "@") { const userId = parts[1]; feeds.push("https://hiverss.com/" + userId + "/feed"); feeds.push("https://hiverss.com/" + userId + "/blog"); feeds.push("https://hiverss.com/" + userId + "/comments"); } } return feeds; })(); --- ^https:\/\/odysee\.com\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); const parts = url.pathname.split("/"); if (parts.length > 1) { const channelname = parts[1]; if (channelname.startsWith("@")) { feeds.push(url.origin + "/$/rss/" + channelname); } } return feeds; })(); --- ^https:\/\/vimeo\.com\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); const parts = url.pathname.split("/"); if (parts.length === 2) { const channelname = parts[1]; if ( ![ "", "watch", "create", "upload", "features", "blog", "for-hire", "stock", "ott", "solutions", "enterprise", "partners", "upgrade", ].includes(channelname) ) { feedUrl = new URL("/" + channelname + "/videos/rss", url.origin); feeds.push(feedUrl.toString()); } } return feeds; })(); --- ^https:\/\/(.*\.)*wikipedia\.org\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); const parts = url.pathname.split("/"); if (parts.length > 1) { const articleTitle = parts[parts.length - 1]; feedUrl = new URL( "/w/index.php?title=" + articleTitle + "&action=history&feed=atom", url.origin ); feeds.push(feedUrl.toString()); feedUrl = new URL( "/w/index.php?title=" + articleTitle + "&action=history&feed=rss", url.origin ); feeds.push(feedUrl.toString()); } return feeds; })(); --- ^https:\/\/github\.com\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); let user; let repo; const parts = url.pathname.split("/"); if (parts.length > 1) { user = parts[1]; feedUrl = new URL(user + ".atom", url.origin); feeds.push(feedUrl.toString()); } if (parts.length > 2) { repo = parts[2]; feedUrl = new URL(user + "/" + repo + "/releases.atom", url.origin); feeds.push(feedUrl.toString()); feedUrl = new URL(user + "/" + repo + "/tags.atom", url.origin); feeds.push(feedUrl.toString()); } return feeds; })(); --- ^https:\/\/www\.reddit\.com\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); feedUrl = new URL(".rss", url.origin); feeds.push(feedUrl.toString()); feedUrl = new URL("/comments/.rss", url.origin); feeds.push(feedUrl.toString()); if (url.pathname.startsWith("/user/")) { const userId = url.pathname.split("/")[2]; feedUrl = new URL("/user/" + userId + "/.rss", url.origin); feeds.push(feedUrl.toString()); feedUrl = new URL("/user/" + userId + "/comments/.rss", url.origin); feeds.push(feedUrl.toString()); feedUrl = new URL("/user/" + userId + "/submitted/.rss", url.origin); feeds.push(feedUrl.toString()); } if (url.pathname.startsWith("/search/") && url.searchParams.has("q")) { feedUrl = new URL("/search.rss", url.origin); feedUrl.searchParams.set("q", url.searchParams.get("q")); feeds.push(feedUrl.toString()); } if (url.pathname.startsWith("/r/")) { const parts = url.pathname.split("/"); if (parts.length > 1) { const subRedditName = parts[2]; feedUrl = new URL("/r/" + subRedditName + "/new/.rss", url.origin); feeds.push(feedUrl.toString()); if (url.pathname.indexOf("/comments/") > 0) { if (parts.length > 3) { const postId = parts[4]; feedUrl = new URL( "/r/" + subRedditName + "/comments/" + postId + "/.rss", url.origin ); feeds.push(feedUrl.toString()); } } } } return feeds; })(); --- ^https:\/\/www\.bitchute\.com\/.* (() => { const feeds = []; let feedUrl; const url = new URL(window.location.href); const parts = url.pathname.split("/"); if (parts.length > 1) { let channelname = ""; switch (parts[1]) { case "channel": case "video": const channelname_selector = "div.channel-banner > div.details > p.name > a:nth-child(1)"; channelname = document .querySelector(channelname_selector) .href.split("/channel/")[1]; break; } if (channelname !== "") { feedUrl = new URL( "/feeds/rss/channel/" + channelname + "?showall=1", url.origin ); feeds.push(feedUrl.toString()); } } return feeds; })(); ```