feedscout 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +10 -7
  2. package/dist/blogrolls/index.cjs +9 -3
  3. package/dist/blogrolls/index.d.cts +1 -1
  4. package/dist/blogrolls/index.d.ts +1 -1
  5. package/dist/blogrolls/index.js +9 -3
  6. package/dist/common/discover/utils.cjs +26 -0
  7. package/dist/common/discover/utils.js +26 -1
  8. package/dist/common/locales.cjs +1 -0
  9. package/dist/common/locales.js +1 -0
  10. package/dist/common/types.d.cts +7 -5
  11. package/dist/common/types.d.ts +7 -5
  12. package/dist/common/uris/headers/index.cjs +6 -3
  13. package/dist/common/uris/headers/index.js +6 -3
  14. package/dist/common/uris/index.cjs +2 -0
  15. package/dist/common/uris/index.js +2 -0
  16. package/dist/common/uris/platform/index.cjs +12 -0
  17. package/dist/common/uris/platform/index.js +11 -0
  18. package/dist/common/uris/platform/types.d.cts +11 -0
  19. package/dist/common/uris/platform/types.d.ts +11 -0
  20. package/dist/common/utils.cjs +10 -0
  21. package/dist/common/utils.d.cts +9 -0
  22. package/dist/common/utils.d.ts +9 -0
  23. package/dist/common/utils.js +7 -1
  24. package/dist/feeds/defaults.cjs +43 -0
  25. package/dist/feeds/defaults.d.cts +3 -1
  26. package/dist/feeds/defaults.d.ts +3 -1
  27. package/dist/feeds/defaults.js +44 -1
  28. package/dist/feeds/index.cjs +10 -3
  29. package/dist/feeds/index.d.cts +1 -1
  30. package/dist/feeds/index.d.ts +1 -1
  31. package/dist/feeds/index.js +11 -4
  32. package/dist/feeds/platform/handlers/behance.cjs +45 -0
  33. package/dist/feeds/platform/handlers/behance.js +45 -0
  34. package/dist/feeds/platform/handlers/blogspot.cjs +24 -0
  35. package/dist/feeds/platform/handlers/blogspot.js +23 -0
  36. package/dist/feeds/platform/handlers/bluesky.cjs +18 -0
  37. package/dist/feeds/platform/handlers/bluesky.js +18 -0
  38. package/dist/feeds/platform/handlers/dailymotion.cjs +66 -0
  39. package/dist/feeds/platform/handlers/dailymotion.js +66 -0
  40. package/dist/feeds/platform/handlers/deviantart.cjs +50 -0
  41. package/dist/feeds/platform/handlers/deviantart.js +50 -0
  42. package/dist/feeds/platform/handlers/devto.cjs +44 -0
  43. package/dist/feeds/platform/handlers/devto.js +44 -0
  44. package/dist/feeds/platform/handlers/github.cjs +89 -0
  45. package/dist/feeds/platform/handlers/github.js +89 -0
  46. package/dist/feeds/platform/handlers/githubGist.cjs +42 -0
  47. package/dist/feeds/platform/handlers/githubGist.js +42 -0
  48. package/dist/feeds/platform/handlers/gitlab.cjs +53 -0
  49. package/dist/feeds/platform/handlers/gitlab.js +53 -0
  50. package/dist/feeds/platform/handlers/kickstarter.cjs +18 -0
  51. package/dist/feeds/platform/handlers/kickstarter.js +18 -0
  52. package/dist/feeds/platform/handlers/lobsters.cjs +34 -0
  53. package/dist/feeds/platform/handlers/lobsters.js +34 -0
  54. package/dist/feeds/platform/handlers/medium.cjs +47 -0
  55. package/dist/feeds/platform/handlers/medium.js +47 -0
  56. package/dist/feeds/platform/handlers/pinterest.cjs +48 -0
  57. package/dist/feeds/platform/handlers/pinterest.js +48 -0
  58. package/dist/feeds/platform/handlers/producthunt.cjs +22 -0
  59. package/dist/feeds/platform/handlers/producthunt.js +22 -0
  60. package/dist/feeds/platform/handlers/reddit.cjs +47 -0
  61. package/dist/feeds/platform/handlers/reddit.js +47 -0
  62. package/dist/feeds/platform/handlers/soundcloud.cjs +37 -0
  63. package/dist/feeds/platform/handlers/soundcloud.js +37 -0
  64. package/dist/feeds/platform/handlers/substack.cjs +15 -0
  65. package/dist/feeds/platform/handlers/substack.js +15 -0
  66. package/dist/feeds/platform/handlers/tumblr.cjs +18 -0
  67. package/dist/feeds/platform/handlers/tumblr.js +18 -0
  68. package/dist/feeds/platform/handlers/wordpress.cjs +30 -0
  69. package/dist/feeds/platform/handlers/wordpress.js +30 -0
  70. package/dist/feeds/platform/handlers/youtube.cjs +56 -0
  71. package/dist/feeds/platform/handlers/youtube.js +56 -0
  72. package/dist/feeds.cjs +1 -0
  73. package/dist/feeds.d.cts +2 -2
  74. package/dist/feeds.d.ts +2 -2
  75. package/dist/feeds.js +2 -2
  76. package/dist/hubs/discover/index.cjs +7 -6
  77. package/dist/hubs/discover/index.js +5 -4
  78. package/dist/hubs/discover/types.d.cts +2 -1
  79. package/dist/hubs/discover/types.d.ts +2 -1
  80. package/dist/hubs/headers/index.cjs +3 -3
  81. package/dist/hubs/headers/index.js +3 -3
  82. package/dist/hubs/html/index.cjs +3 -3
  83. package/dist/hubs/html/index.js +3 -3
  84. package/dist/index.d.cts +2 -2
  85. package/dist/index.d.ts +2 -2
  86. package/dist/utils.cjs +8 -0
  87. package/dist/utils.d.cts +2 -0
  88. package/dist/utils.d.ts +2 -0
  89. package/dist/utils.js +3 -0
  90. package/package.json +32 -32
  91. package/dist/adapters.cjs +0 -6
  92. package/dist/adapters.d.cts +0 -2
  93. package/dist/adapters.d.ts +0 -2
  94. package/dist/adapters.js +0 -3
  95. package/dist/common/discover/adapters.cjs +0 -76
  96. package/dist/common/discover/adapters.d.cts +0 -10
  97. package/dist/common/discover/adapters.d.ts +0 -10
  98. package/dist/common/discover/adapters.js +0 -72
@@ -0,0 +1,89 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/github.ts
4
+ const hosts = ["github.com", "www.github.com"];
5
+ const excludedPaths = [
6
+ "about",
7
+ "account",
8
+ "apps",
9
+ "blog",
10
+ "careers",
11
+ "codespaces",
12
+ "collections",
13
+ "contact",
14
+ "copilot",
15
+ "customer-stories",
16
+ "dashboard",
17
+ "education",
18
+ "enterprise",
19
+ "events",
20
+ "explore",
21
+ "features",
22
+ "feed",
23
+ "home",
24
+ "issues",
25
+ "join",
26
+ "login",
27
+ "marketplace",
28
+ "new",
29
+ "nonprofit",
30
+ "notifications",
31
+ "organizations",
32
+ "orgs",
33
+ "password_reset",
34
+ "premium-support",
35
+ "pricing",
36
+ "pulls",
37
+ "readme",
38
+ "resources",
39
+ "search",
40
+ "security",
41
+ "sessions",
42
+ "settings",
43
+ "site",
44
+ "sponsors",
45
+ "stars",
46
+ "team",
47
+ "topics",
48
+ "trending",
49
+ "watching"
50
+ ];
51
+ const githubHandler = {
52
+ match: (url) => {
53
+ return require_utils.isHostOf(url, hosts);
54
+ },
55
+ resolve: (url) => {
56
+ const { pathname } = new URL(url);
57
+ const uris = [];
58
+ const userMatch = pathname.match(/^\/([^/]+)\/?$/);
59
+ if (userMatch?.[1] && !require_utils.isAnyOf(userMatch[1], excludedPaths)) {
60
+ const user = userMatch[1];
61
+ uris.push(`https://github.com/${user}.atom`);
62
+ return uris;
63
+ }
64
+ const repoMatch = pathname.match(/^\/([^/]+)\/([^/]+)/);
65
+ const owner = repoMatch?.[1];
66
+ const repo = repoMatch?.[2];
67
+ if (!owner || !repo || require_utils.isAnyOf(owner, excludedPaths)) return [];
68
+ uris.push(`https://github.com/${owner}/${repo}/releases.atom`);
69
+ uris.push(`https://github.com/${owner}/${repo}/commits.atom`);
70
+ uris.push(`https://github.com/${owner}/${repo}/tags.atom`);
71
+ if (/\/wiki(\/|$)/.test(pathname)) uris.push(`https://github.com/${owner}/${repo}/wiki.atom`);
72
+ if (/\/discussions(\/|$)/.test(pathname)) uris.push(`https://github.com/${owner}/${repo}/discussions.atom`);
73
+ const branchMatch = pathname.match(/^\/[^/]+\/[^/]+\/tree\/([^/]+)\/?$/);
74
+ if (branchMatch?.[1]) {
75
+ const branch = branchMatch[1];
76
+ uris.push(`https://github.com/${owner}/${repo}/commits/${branch}.atom`);
77
+ }
78
+ const fileMatch = pathname.match(/^\/[^/]+\/[^/]+\/(?:blob|commits)\/([^/]+)\/(.+)/);
79
+ if (fileMatch?.[1] && fileMatch?.[2]) {
80
+ const branch = fileMatch[1];
81
+ const filePath = fileMatch[2];
82
+ uris.push(`https://github.com/${owner}/${repo}/commits/${branch}/${filePath}.atom`);
83
+ }
84
+ return uris;
85
+ }
86
+ };
87
+
88
+ //#endregion
89
+ exports.githubHandler = githubHandler;
@@ -0,0 +1,89 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/github.ts
4
+ const hosts = ["github.com", "www.github.com"];
5
+ const excludedPaths = [
6
+ "about",
7
+ "account",
8
+ "apps",
9
+ "blog",
10
+ "careers",
11
+ "codespaces",
12
+ "collections",
13
+ "contact",
14
+ "copilot",
15
+ "customer-stories",
16
+ "dashboard",
17
+ "education",
18
+ "enterprise",
19
+ "events",
20
+ "explore",
21
+ "features",
22
+ "feed",
23
+ "home",
24
+ "issues",
25
+ "join",
26
+ "login",
27
+ "marketplace",
28
+ "new",
29
+ "nonprofit",
30
+ "notifications",
31
+ "organizations",
32
+ "orgs",
33
+ "password_reset",
34
+ "premium-support",
35
+ "pricing",
36
+ "pulls",
37
+ "readme",
38
+ "resources",
39
+ "search",
40
+ "security",
41
+ "sessions",
42
+ "settings",
43
+ "site",
44
+ "sponsors",
45
+ "stars",
46
+ "team",
47
+ "topics",
48
+ "trending",
49
+ "watching"
50
+ ];
51
+ const githubHandler = {
52
+ match: (url) => {
53
+ return isHostOf(url, hosts);
54
+ },
55
+ resolve: (url) => {
56
+ const { pathname } = new URL(url);
57
+ const uris = [];
58
+ const userMatch = pathname.match(/^\/([^/]+)\/?$/);
59
+ if (userMatch?.[1] && !isAnyOf(userMatch[1], excludedPaths)) {
60
+ const user = userMatch[1];
61
+ uris.push(`https://github.com/${user}.atom`);
62
+ return uris;
63
+ }
64
+ const repoMatch = pathname.match(/^\/([^/]+)\/([^/]+)/);
65
+ const owner = repoMatch?.[1];
66
+ const repo = repoMatch?.[2];
67
+ if (!owner || !repo || isAnyOf(owner, excludedPaths)) return [];
68
+ uris.push(`https://github.com/${owner}/${repo}/releases.atom`);
69
+ uris.push(`https://github.com/${owner}/${repo}/commits.atom`);
70
+ uris.push(`https://github.com/${owner}/${repo}/tags.atom`);
71
+ if (/\/wiki(\/|$)/.test(pathname)) uris.push(`https://github.com/${owner}/${repo}/wiki.atom`);
72
+ if (/\/discussions(\/|$)/.test(pathname)) uris.push(`https://github.com/${owner}/${repo}/discussions.atom`);
73
+ const branchMatch = pathname.match(/^\/[^/]+\/[^/]+\/tree\/([^/]+)\/?$/);
74
+ if (branchMatch?.[1]) {
75
+ const branch = branchMatch[1];
76
+ uris.push(`https://github.com/${owner}/${repo}/commits/${branch}.atom`);
77
+ }
78
+ const fileMatch = pathname.match(/^\/[^/]+\/[^/]+\/(?:blob|commits)\/([^/]+)\/(.+)/);
79
+ if (fileMatch?.[1] && fileMatch?.[2]) {
80
+ const branch = fileMatch[1];
81
+ const filePath = fileMatch[2];
82
+ uris.push(`https://github.com/${owner}/${repo}/commits/${branch}/${filePath}.atom`);
83
+ }
84
+ return uris;
85
+ }
86
+ };
87
+
88
+ //#endregion
89
+ export { githubHandler };
@@ -0,0 +1,42 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/githubGist.ts
4
+ const hosts = ["gist.github.com"];
5
+ const excludedPaths = [
6
+ "discover",
7
+ "search",
8
+ "login",
9
+ "join",
10
+ "settings"
11
+ ];
12
+ const githubGistHandler = {
13
+ match: (url) => {
14
+ return require_utils.isHostOf(url, hosts);
15
+ },
16
+ resolve: (url) => {
17
+ const { pathname } = new URL(url);
18
+ const uris = [];
19
+ const gistMatch = pathname.match(/^\/([^/]+)\/([a-f0-9]+)/);
20
+ if (gistMatch?.[1] && gistMatch?.[2]) {
21
+ const username = gistMatch[1];
22
+ if (!require_utils.isAnyOf(username, excludedPaths)) uris.push(`https://gist.github.com/${username}.atom`);
23
+ return uris;
24
+ }
25
+ const starredMatch = pathname.match(/^\/([^/]+)\/starred\/?$/);
26
+ if (starredMatch?.[1] && !require_utils.isAnyOf(starredMatch[1], excludedPaths)) {
27
+ const username = starredMatch[1];
28
+ uris.push(`https://gist.github.com/${username}/starred.atom`);
29
+ return uris;
30
+ }
31
+ const userMatch = pathname.match(/^\/([^/]+)\/?$/);
32
+ if (userMatch?.[1] && !require_utils.isAnyOf(userMatch[1], excludedPaths)) {
33
+ const username = userMatch[1];
34
+ uris.push(`https://gist.github.com/${username}.atom`);
35
+ return uris;
36
+ }
37
+ return [];
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ exports.githubGistHandler = githubGistHandler;
@@ -0,0 +1,42 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/githubGist.ts
4
+ const hosts = ["gist.github.com"];
5
+ const excludedPaths = [
6
+ "discover",
7
+ "search",
8
+ "login",
9
+ "join",
10
+ "settings"
11
+ ];
12
+ const githubGistHandler = {
13
+ match: (url) => {
14
+ return isHostOf(url, hosts);
15
+ },
16
+ resolve: (url) => {
17
+ const { pathname } = new URL(url);
18
+ const uris = [];
19
+ const gistMatch = pathname.match(/^\/([^/]+)\/([a-f0-9]+)/);
20
+ if (gistMatch?.[1] && gistMatch?.[2]) {
21
+ const username = gistMatch[1];
22
+ if (!isAnyOf(username, excludedPaths)) uris.push(`https://gist.github.com/${username}.atom`);
23
+ return uris;
24
+ }
25
+ const starredMatch = pathname.match(/^\/([^/]+)\/starred\/?$/);
26
+ if (starredMatch?.[1] && !isAnyOf(starredMatch[1], excludedPaths)) {
27
+ const username = starredMatch[1];
28
+ uris.push(`https://gist.github.com/${username}/starred.atom`);
29
+ return uris;
30
+ }
31
+ const userMatch = pathname.match(/^\/([^/]+)\/?$/);
32
+ if (userMatch?.[1] && !isAnyOf(userMatch[1], excludedPaths)) {
33
+ const username = userMatch[1];
34
+ uris.push(`https://gist.github.com/${username}.atom`);
35
+ return uris;
36
+ }
37
+ return [];
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ export { githubGistHandler };
@@ -0,0 +1,53 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/gitlab.ts
4
+ const hosts = ["gitlab.com", "www.gitlab.com"];
5
+ const excludedPaths = [
6
+ "explore",
7
+ "dashboard",
8
+ "projects",
9
+ "groups",
10
+ "search",
11
+ "admin",
12
+ "help",
13
+ "assets",
14
+ "users",
15
+ "api",
16
+ "jwt",
17
+ "oauth",
18
+ "profile",
19
+ "snippets",
20
+ "abuse_reports",
21
+ "invites",
22
+ "import",
23
+ "uploads",
24
+ "robots.txt",
25
+ "sitemap",
26
+ "-"
27
+ ];
28
+ const gitlabHandler = {
29
+ match: (url) => {
30
+ return require_utils.isHostOf(url, hosts);
31
+ },
32
+ resolve: (url) => {
33
+ const { origin, pathname } = new URL(url);
34
+ const pathSegments = pathname.split("/").filter(Boolean);
35
+ if (pathSegments.length === 1) {
36
+ const user = pathSegments[0];
37
+ if (!require_utils.isAnyOf(user, excludedPaths)) return [`${origin}/${user}.atom`];
38
+ }
39
+ if (pathSegments.length >= 2) {
40
+ const user = pathSegments[0];
41
+ const repo = pathSegments[1];
42
+ if (!require_utils.isAnyOf(user, excludedPaths)) return [
43
+ `${origin}/${user}/${repo}/-/releases.atom`,
44
+ `${origin}/${user}/${repo}/-/tags?format=atom`,
45
+ `${origin}/${user}/${repo}.atom`
46
+ ];
47
+ }
48
+ return [];
49
+ }
50
+ };
51
+
52
+ //#endregion
53
+ exports.gitlabHandler = gitlabHandler;
@@ -0,0 +1,53 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/gitlab.ts
4
+ const hosts = ["gitlab.com", "www.gitlab.com"];
5
+ const excludedPaths = [
6
+ "explore",
7
+ "dashboard",
8
+ "projects",
9
+ "groups",
10
+ "search",
11
+ "admin",
12
+ "help",
13
+ "assets",
14
+ "users",
15
+ "api",
16
+ "jwt",
17
+ "oauth",
18
+ "profile",
19
+ "snippets",
20
+ "abuse_reports",
21
+ "invites",
22
+ "import",
23
+ "uploads",
24
+ "robots.txt",
25
+ "sitemap",
26
+ "-"
27
+ ];
28
+ const gitlabHandler = {
29
+ match: (url) => {
30
+ return isHostOf(url, hosts);
31
+ },
32
+ resolve: (url) => {
33
+ const { origin, pathname } = new URL(url);
34
+ const pathSegments = pathname.split("/").filter(Boolean);
35
+ if (pathSegments.length === 1) {
36
+ const user = pathSegments[0];
37
+ if (!isAnyOf(user, excludedPaths)) return [`${origin}/${user}.atom`];
38
+ }
39
+ if (pathSegments.length >= 2) {
40
+ const user = pathSegments[0];
41
+ const repo = pathSegments[1];
42
+ if (!isAnyOf(user, excludedPaths)) return [
43
+ `${origin}/${user}/${repo}/-/releases.atom`,
44
+ `${origin}/${user}/${repo}/-/tags?format=atom`,
45
+ `${origin}/${user}/${repo}.atom`
46
+ ];
47
+ }
48
+ return [];
49
+ }
50
+ };
51
+
52
+ //#endregion
53
+ export { gitlabHandler };
@@ -0,0 +1,18 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/kickstarter.ts
4
+ const hosts = ["kickstarter.com", "www.kickstarter.com"];
5
+ const kickstarterHandler = {
6
+ match: (url) => {
7
+ return require_utils.isHostOf(url, hosts);
8
+ },
9
+ resolve: (url) => {
10
+ const { pathname } = new URL(url);
11
+ const pathSegments = pathname.split("/").filter(Boolean);
12
+ if (pathSegments.length >= 3 && pathSegments[0] === "projects") return [`https://www.kickstarter.com/projects/${pathSegments[1]}/${pathSegments[2]}/posts.atom`];
13
+ return ["https://www.kickstarter.com/projects/feed.atom"];
14
+ }
15
+ };
16
+
17
+ //#endregion
18
+ exports.kickstarterHandler = kickstarterHandler;
@@ -0,0 +1,18 @@
1
+ import { isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/kickstarter.ts
4
+ const hosts = ["kickstarter.com", "www.kickstarter.com"];
5
+ const kickstarterHandler = {
6
+ match: (url) => {
7
+ return isHostOf(url, hosts);
8
+ },
9
+ resolve: (url) => {
10
+ const { pathname } = new URL(url);
11
+ const pathSegments = pathname.split("/").filter(Boolean);
12
+ if (pathSegments.length >= 3 && pathSegments[0] === "projects") return [`https://www.kickstarter.com/projects/${pathSegments[1]}/${pathSegments[2]}/posts.atom`];
13
+ return ["https://www.kickstarter.com/projects/feed.atom"];
14
+ }
15
+ };
16
+
17
+ //#endregion
18
+ export { kickstarterHandler };
@@ -0,0 +1,34 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/lobsters.ts
4
+ const hosts = ["lobste.rs"];
5
+ const tagPathRegex = /^\/t\/([a-zA-Z0-9,_-]+)/;
6
+ const domainPathRegex = /^\/domains\/([^/]+)/;
7
+ const userPathRegex = /^\/~([a-zA-Z0-9_-]+)/;
8
+ const topPathRegex = /^\/top(?:\/(1d|3d|1w|1m|1y))?\/?$/;
9
+ const lobstersHandler = {
10
+ match: (url) => {
11
+ return require_utils.isHostOf(url, hosts);
12
+ },
13
+ resolve: (url) => {
14
+ const { pathname } = new URL(url);
15
+ const tagMatch = pathname.match(tagPathRegex);
16
+ if (tagMatch?.[1]) return [`https://lobste.rs/t/${tagMatch[1]}.rss`];
17
+ const domainMatch = pathname.match(domainPathRegex);
18
+ if (domainMatch?.[1]) return [`https://lobste.rs/domains/${domainMatch[1]}.rss`];
19
+ const userMatch = pathname.match(userPathRegex);
20
+ if (userMatch?.[1]) return [`https://lobste.rs/~${userMatch[1]}/stories.rss`];
21
+ const topMatch = pathname.match(topPathRegex);
22
+ if (topMatch) {
23
+ const period = topMatch[1];
24
+ if (period) return [`https://lobste.rs/top/${period}/rss`];
25
+ return ["https://lobste.rs/top/rss"];
26
+ }
27
+ if (pathname === "/newest" || pathname === "/newest/") return ["https://lobste.rs/newest.rss"];
28
+ if (pathname === "/comments" || pathname === "/comments/") return ["https://lobste.rs/comments.rss"];
29
+ return ["https://lobste.rs/rss"];
30
+ }
31
+ };
32
+
33
+ //#endregion
34
+ exports.lobstersHandler = lobstersHandler;
@@ -0,0 +1,34 @@
1
+ import { isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/lobsters.ts
4
+ const hosts = ["lobste.rs"];
5
+ const tagPathRegex = /^\/t\/([a-zA-Z0-9,_-]+)/;
6
+ const domainPathRegex = /^\/domains\/([^/]+)/;
7
+ const userPathRegex = /^\/~([a-zA-Z0-9_-]+)/;
8
+ const topPathRegex = /^\/top(?:\/(1d|3d|1w|1m|1y))?\/?$/;
9
+ const lobstersHandler = {
10
+ match: (url) => {
11
+ return isHostOf(url, hosts);
12
+ },
13
+ resolve: (url) => {
14
+ const { pathname } = new URL(url);
15
+ const tagMatch = pathname.match(tagPathRegex);
16
+ if (tagMatch?.[1]) return [`https://lobste.rs/t/${tagMatch[1]}.rss`];
17
+ const domainMatch = pathname.match(domainPathRegex);
18
+ if (domainMatch?.[1]) return [`https://lobste.rs/domains/${domainMatch[1]}.rss`];
19
+ const userMatch = pathname.match(userPathRegex);
20
+ if (userMatch?.[1]) return [`https://lobste.rs/~${userMatch[1]}/stories.rss`];
21
+ const topMatch = pathname.match(topPathRegex);
22
+ if (topMatch) {
23
+ const period = topMatch[1];
24
+ if (period) return [`https://lobste.rs/top/${period}/rss`];
25
+ return ["https://lobste.rs/top/rss"];
26
+ }
27
+ if (pathname === "/newest" || pathname === "/newest/") return ["https://lobste.rs/newest.rss"];
28
+ if (pathname === "/comments" || pathname === "/comments/") return ["https://lobste.rs/comments.rss"];
29
+ return ["https://lobste.rs/rss"];
30
+ }
31
+ };
32
+
33
+ //#endregion
34
+ export { lobstersHandler };
@@ -0,0 +1,47 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/medium.ts
4
+ const hosts = ["medium.com", "www.medium.com"];
5
+ const excludedPaths = [
6
+ "search",
7
+ "me",
8
+ "new-story",
9
+ "plans",
10
+ "membership"
11
+ ];
12
+ const mediumHandler = {
13
+ match: (url) => {
14
+ return require_utils.isHostOf(url, hosts) || require_utils.isSubdomainOf(url, "medium.com");
15
+ },
16
+ resolve: (url) => {
17
+ const { hostname, pathname } = new URL(url);
18
+ const lowerHostname = hostname.toLowerCase();
19
+ if (hosts.includes(lowerHostname)) {
20
+ const userMatch = pathname.match(/^\/@([^/]+)/);
21
+ if (userMatch?.[1]) return [`https://medium.com/feed/@${userMatch[1]}`];
22
+ const tagMatch = pathname.match(/^\/tag\/([^/]+)/);
23
+ if (tagMatch?.[1]) return [`https://medium.com/feed/tag/${tagMatch[1]}`];
24
+ const pubTagMatch = pathname.match(/^\/([^/@][^/]+)\/tagged\/([^/]+)/);
25
+ if (pubTagMatch?.[1] && pubTagMatch?.[2]) {
26
+ const publication = pubTagMatch[1];
27
+ const tag = pubTagMatch[2];
28
+ if (!require_utils.isAnyOf(publication, excludedPaths)) return [`https://medium.com/feed/${publication}/tagged/${tag}`];
29
+ }
30
+ const pubMatch = pathname.match(/^\/([^/@][^/]+)/);
31
+ if (pubMatch?.[1]) {
32
+ const publication = pubMatch[1];
33
+ if (!require_utils.isAnyOf(publication, excludedPaths)) return [`https://medium.com/feed/${publication}`];
34
+ }
35
+ }
36
+ if (lowerHostname.endsWith(".medium.com") && lowerHostname !== "medium.com" && lowerHostname !== "www.medium.com") {
37
+ const subdomain = lowerHostname.replace(".medium.com", "");
38
+ const tagMatch = pathname.match(/^\/tagged\/([^/]+)/);
39
+ if (tagMatch?.[1]) return [`https://medium.com/feed/${subdomain}/tagged/${tagMatch[1]}`];
40
+ return [`https://medium.com/feed/${subdomain}`];
41
+ }
42
+ return [];
43
+ }
44
+ };
45
+
46
+ //#endregion
47
+ exports.mediumHandler = mediumHandler;
@@ -0,0 +1,47 @@
1
+ import { isAnyOf, isHostOf, isSubdomainOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/medium.ts
4
+ const hosts = ["medium.com", "www.medium.com"];
5
+ const excludedPaths = [
6
+ "search",
7
+ "me",
8
+ "new-story",
9
+ "plans",
10
+ "membership"
11
+ ];
12
+ const mediumHandler = {
13
+ match: (url) => {
14
+ return isHostOf(url, hosts) || isSubdomainOf(url, "medium.com");
15
+ },
16
+ resolve: (url) => {
17
+ const { hostname, pathname } = new URL(url);
18
+ const lowerHostname = hostname.toLowerCase();
19
+ if (hosts.includes(lowerHostname)) {
20
+ const userMatch = pathname.match(/^\/@([^/]+)/);
21
+ if (userMatch?.[1]) return [`https://medium.com/feed/@${userMatch[1]}`];
22
+ const tagMatch = pathname.match(/^\/tag\/([^/]+)/);
23
+ if (tagMatch?.[1]) return [`https://medium.com/feed/tag/${tagMatch[1]}`];
24
+ const pubTagMatch = pathname.match(/^\/([^/@][^/]+)\/tagged\/([^/]+)/);
25
+ if (pubTagMatch?.[1] && pubTagMatch?.[2]) {
26
+ const publication = pubTagMatch[1];
27
+ const tag = pubTagMatch[2];
28
+ if (!isAnyOf(publication, excludedPaths)) return [`https://medium.com/feed/${publication}/tagged/${tag}`];
29
+ }
30
+ const pubMatch = pathname.match(/^\/([^/@][^/]+)/);
31
+ if (pubMatch?.[1]) {
32
+ const publication = pubMatch[1];
33
+ if (!isAnyOf(publication, excludedPaths)) return [`https://medium.com/feed/${publication}`];
34
+ }
35
+ }
36
+ if (lowerHostname.endsWith(".medium.com") && lowerHostname !== "medium.com" && lowerHostname !== "www.medium.com") {
37
+ const subdomain = lowerHostname.replace(".medium.com", "");
38
+ const tagMatch = pathname.match(/^\/tagged\/([^/]+)/);
39
+ if (tagMatch?.[1]) return [`https://medium.com/feed/${subdomain}/tagged/${tagMatch[1]}`];
40
+ return [`https://medium.com/feed/${subdomain}`];
41
+ }
42
+ return [];
43
+ }
44
+ };
45
+
46
+ //#endregion
47
+ export { mediumHandler };
@@ -0,0 +1,48 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/pinterest.ts
4
+ const hosts = [
5
+ "pinterest.com",
6
+ "www.pinterest.com",
7
+ "pin.it"
8
+ ];
9
+ const excludedPaths = [
10
+ "_",
11
+ "about",
12
+ "business",
13
+ "convert",
14
+ "explore",
15
+ "ideas",
16
+ "login",
17
+ "news_hub",
18
+ "password",
19
+ "pin",
20
+ "privacy",
21
+ "resource",
22
+ "search",
23
+ "settings",
24
+ "terms",
25
+ "today",
26
+ "topics"
27
+ ];
28
+ const pinterestHandler = {
29
+ match: (url) => {
30
+ return require_utils.isHostOf(url, hosts);
31
+ },
32
+ resolve: (url) => {
33
+ const { pathname } = new URL(url);
34
+ const pathSegments = pathname.split("/").filter(Boolean);
35
+ if (pathSegments.length === 0) return [];
36
+ const username = pathSegments[0];
37
+ if (require_utils.isAnyOf(username, excludedPaths)) return [];
38
+ if (pathSegments.length >= 2) {
39
+ const boardname = pathSegments[1];
40
+ if (boardname.startsWith("_") || boardname === "pins" || boardname === "boards") return [`https://www.pinterest.com/${username}/feed.rss`];
41
+ return [`https://www.pinterest.com/${username}/${boardname}.rss`];
42
+ }
43
+ return [`https://www.pinterest.com/${username}/feed.rss`];
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ exports.pinterestHandler = pinterestHandler;
@@ -0,0 +1,48 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/pinterest.ts
4
+ const hosts = [
5
+ "pinterest.com",
6
+ "www.pinterest.com",
7
+ "pin.it"
8
+ ];
9
+ const excludedPaths = [
10
+ "_",
11
+ "about",
12
+ "business",
13
+ "convert",
14
+ "explore",
15
+ "ideas",
16
+ "login",
17
+ "news_hub",
18
+ "password",
19
+ "pin",
20
+ "privacy",
21
+ "resource",
22
+ "search",
23
+ "settings",
24
+ "terms",
25
+ "today",
26
+ "topics"
27
+ ];
28
+ const pinterestHandler = {
29
+ match: (url) => {
30
+ return isHostOf(url, hosts);
31
+ },
32
+ resolve: (url) => {
33
+ const { pathname } = new URL(url);
34
+ const pathSegments = pathname.split("/").filter(Boolean);
35
+ if (pathSegments.length === 0) return [];
36
+ const username = pathSegments[0];
37
+ if (isAnyOf(username, excludedPaths)) return [];
38
+ if (pathSegments.length >= 2) {
39
+ const boardname = pathSegments[1];
40
+ if (boardname.startsWith("_") || boardname === "pins" || boardname === "boards") return [`https://www.pinterest.com/${username}/feed.rss`];
41
+ return [`https://www.pinterest.com/${username}/${boardname}.rss`];
42
+ }
43
+ return [`https://www.pinterest.com/${username}/feed.rss`];
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ export { pinterestHandler };