Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
atomGit opened this issue Jan 8, 2019 · 9 comments
Open

Comments

@atomGit
Copy link

atomGit commented Jan 8, 2019

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
Copy link
Owner

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
Copy link
Author

atomGit commented Jan 8, 2019

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
Copy link
Owner

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

  • First: there may be a case of multiple feeds (i.e for youtube: channel feed, playlist feed, video comments feed)
  • Second: sometimes link is not that easily obtained as in your example (like, get token from meta from head tag, and concatenate it with part of url, or even more, via ajax call). It's not area of current extension to handle such things as it just will bloat the extension.

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
Copy link
Author

atomGit commented Jan 8, 2019

thanks for the explanation

@atomGit atomGit closed this as completed Jan 8, 2019
@Reeywhaar
Copy link
Owner

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

@atomGit
Copy link
Author

atomGit commented Jan 8, 2019

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
Copy link
Author

atomGit commented Jan 8, 2019

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

wadif somebody somewhere (mainly you, here ❤️ ) 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
Copy link
Owner

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
Copy link
Author

atomGit commented Nov 24, 2023

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
^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;
})();

@atomGit atomGit reopened this Nov 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants