feedscout 1.1.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 (80) hide show
  1. package/README.md +8 -6
  2. package/dist/blogrolls/index.cjs +8 -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 +8 -3
  6. package/dist/common/discover/utils.cjs +14 -0
  7. package/dist/common/discover/utils.js +14 -1
  8. package/dist/common/types.d.cts +4 -4
  9. package/dist/common/types.d.ts +4 -4
  10. package/dist/common/uris/headers/index.cjs +6 -3
  11. package/dist/common/uris/headers/index.js +6 -3
  12. package/dist/common/utils.cjs +1 -0
  13. package/dist/common/utils.d.cts +9 -0
  14. package/dist/common/utils.d.ts +9 -0
  15. package/dist/common/utils.js +1 -1
  16. package/dist/feeds/defaults.cjs +18 -0
  17. package/dist/feeds/defaults.js +18 -0
  18. package/dist/feeds/index.cjs +9 -3
  19. package/dist/feeds/index.d.cts +1 -1
  20. package/dist/feeds/index.d.ts +1 -1
  21. package/dist/feeds/index.js +9 -3
  22. package/dist/feeds/platform/handlers/behance.cjs +45 -0
  23. package/dist/feeds/platform/handlers/behance.js +45 -0
  24. package/dist/feeds/platform/handlers/blogspot.cjs +13 -4
  25. package/dist/feeds/platform/handlers/blogspot.js +13 -5
  26. package/dist/feeds/platform/handlers/dailymotion.cjs +66 -0
  27. package/dist/feeds/platform/handlers/dailymotion.js +66 -0
  28. package/dist/feeds/platform/handlers/deviantart.cjs +50 -0
  29. package/dist/feeds/platform/handlers/deviantart.js +50 -0
  30. package/dist/feeds/platform/handlers/devto.cjs +44 -0
  31. package/dist/feeds/platform/handlers/devto.js +44 -0
  32. package/dist/feeds/platform/handlers/github.cjs +9 -3
  33. package/dist/feeds/platform/handlers/github.js +9 -3
  34. package/dist/feeds/platform/handlers/githubGist.cjs +42 -0
  35. package/dist/feeds/platform/handlers/githubGist.js +42 -0
  36. package/dist/feeds/platform/handlers/gitlab.cjs +36 -2
  37. package/dist/feeds/platform/handlers/gitlab.js +37 -3
  38. package/dist/feeds/platform/handlers/kickstarter.cjs +4 -7
  39. package/dist/feeds/platform/handlers/kickstarter.js +4 -7
  40. package/dist/feeds/platform/handlers/lobsters.cjs +34 -0
  41. package/dist/feeds/platform/handlers/lobsters.js +34 -0
  42. package/dist/feeds/platform/handlers/medium.cjs +47 -0
  43. package/dist/feeds/platform/handlers/medium.js +47 -0
  44. package/dist/feeds/platform/handlers/pinterest.cjs +48 -0
  45. package/dist/feeds/platform/handlers/pinterest.js +48 -0
  46. package/dist/feeds/platform/handlers/producthunt.cjs +22 -0
  47. package/dist/feeds/platform/handlers/producthunt.js +22 -0
  48. package/dist/feeds/platform/handlers/reddit.cjs +3 -0
  49. package/dist/feeds/platform/handlers/reddit.js +3 -0
  50. package/dist/feeds/platform/handlers/soundcloud.cjs +1 -1
  51. package/dist/feeds/platform/handlers/soundcloud.js +2 -2
  52. package/dist/feeds/platform/handlers/tumblr.cjs +4 -1
  53. package/dist/feeds/platform/handlers/tumblr.js +4 -1
  54. package/dist/feeds/platform/handlers/wordpress.cjs +17 -6
  55. package/dist/feeds/platform/handlers/wordpress.js +17 -6
  56. package/dist/feeds/platform/handlers/youtube.cjs +16 -4
  57. package/dist/feeds/platform/handlers/youtube.js +16 -4
  58. package/dist/hubs/discover/index.cjs +7 -6
  59. package/dist/hubs/discover/index.js +5 -4
  60. package/dist/hubs/discover/types.d.cts +2 -1
  61. package/dist/hubs/discover/types.d.ts +2 -1
  62. package/dist/hubs/headers/index.cjs +3 -3
  63. package/dist/hubs/headers/index.js +3 -3
  64. package/dist/hubs/html/index.cjs +3 -3
  65. package/dist/hubs/html/index.js +3 -3
  66. package/dist/index.d.cts +2 -2
  67. package/dist/index.d.ts +2 -2
  68. package/dist/utils.cjs +8 -0
  69. package/dist/utils.d.cts +2 -0
  70. package/dist/utils.d.ts +2 -0
  71. package/dist/utils.js +3 -0
  72. package/package.json +18 -19
  73. package/dist/adapters.cjs +0 -6
  74. package/dist/adapters.d.cts +0 -2
  75. package/dist/adapters.d.ts +0 -2
  76. package/dist/adapters.js +0 -3
  77. package/dist/common/discover/adapters.cjs +0 -76
  78. package/dist/common/discover/adapters.d.cts +0 -10
  79. package/dist/common/discover/adapters.d.ts +0 -10
  80. package/dist/common/discover/adapters.js +0 -72
@@ -0,0 +1,66 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/dailymotion.ts
4
+ const hosts = ["dailymotion.com", "www.dailymotion.com"];
5
+ const userPathRegex = /^\/([a-zA-Z0-9_-]+)$/;
6
+ const playlistPathRegex = /^\/playlist\/([a-zA-Z0-9_-]+)/;
7
+ const excludedPaths = [
8
+ "signin",
9
+ "signout",
10
+ "signup",
11
+ "login",
12
+ "logout",
13
+ "register",
14
+ "search",
15
+ "legal",
16
+ "about",
17
+ "careers",
18
+ "terms",
19
+ "privacy",
20
+ "feedback",
21
+ "help",
22
+ "settings",
23
+ "upload",
24
+ "partner",
25
+ "monetize",
26
+ "studio",
27
+ "video",
28
+ "live",
29
+ "channels",
30
+ "playlist",
31
+ "topics",
32
+ "trending",
33
+ "dm",
34
+ "creator",
35
+ "premium",
36
+ "explore",
37
+ "following",
38
+ "subscriptions",
39
+ "notifications",
40
+ "history",
41
+ "watch",
42
+ "contact",
43
+ "ads",
44
+ "dmca",
45
+ "copyright",
46
+ "community"
47
+ ];
48
+ const dailymotionHandler = {
49
+ match: (url) => {
50
+ return isHostOf(url, hosts);
51
+ },
52
+ resolve: (url) => {
53
+ const { pathname } = new URL(url);
54
+ const playlistMatch = pathname.match(playlistPathRegex);
55
+ if (playlistMatch?.[1]) return [`https://www.dailymotion.com/rss/playlist/${playlistMatch[1]}`];
56
+ const userMatch = pathname.match(userPathRegex);
57
+ if (userMatch?.[1]) {
58
+ const username = userMatch[1];
59
+ if (!isAnyOf(username, excludedPaths)) return [`https://www.dailymotion.com/rss/${username}`];
60
+ }
61
+ return [];
62
+ }
63
+ };
64
+
65
+ //#endregion
66
+ export { dailymotionHandler };
@@ -0,0 +1,50 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/deviantart.ts
4
+ const hosts = ["deviantart.com", "www.deviantart.com"];
5
+ const feedBaseUrl = "https://backend.deviantart.com/rss.xml";
6
+ const excludedPaths = [
7
+ "about",
8
+ "join",
9
+ "search",
10
+ "topic",
11
+ "watch",
12
+ "notifications",
13
+ "settings",
14
+ "submit",
15
+ "shop",
16
+ "core-membership",
17
+ "team",
18
+ "developers"
19
+ ];
20
+ const deviantartHandler = {
21
+ match: (url) => {
22
+ return require_utils.isHostOf(url, hosts);
23
+ },
24
+ resolve: (url) => {
25
+ const { pathname } = new URL(url);
26
+ const tagMatch = pathname.match(/^\/tag\/([^/]+)/);
27
+ if (tagMatch?.[1]) {
28
+ const tag = tagMatch[1];
29
+ return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(`tag:${tag}`)}`];
30
+ }
31
+ const favMatch = pathname.match(/^\/([a-zA-Z0-9_-]+)\/favourites\/?$/);
32
+ if (favMatch?.[1]) {
33
+ const username = favMatch[1];
34
+ if (!require_utils.isAnyOf(username, excludedPaths)) return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(`favby:${username}`)}`];
35
+ }
36
+ const folderMatch = pathname.match(/^\/([a-zA-Z0-9_-]+)\/gallery\/(\d+)(?:\/|$)/);
37
+ if (folderMatch?.[1] && folderMatch?.[2]) {
38
+ const username = folderMatch[1];
39
+ const folderId = folderMatch[2];
40
+ if (!require_utils.isAnyOf(username, excludedPaths)) return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(`gallery:${username}/${folderId}`)}`];
41
+ }
42
+ const username = pathname.match(/^\/([a-zA-Z0-9_-]+)(?:\/gallery(?:\/all)?)?(?:\/|$)/)?.[1];
43
+ if (!username || require_utils.isAnyOf(username, excludedPaths)) return [];
44
+ const query = `by:${username} sort:time meta:all`;
45
+ return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(query)}`];
46
+ }
47
+ };
48
+
49
+ //#endregion
50
+ exports.deviantartHandler = deviantartHandler;
@@ -0,0 +1,50 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/deviantart.ts
4
+ const hosts = ["deviantart.com", "www.deviantart.com"];
5
+ const feedBaseUrl = "https://backend.deviantart.com/rss.xml";
6
+ const excludedPaths = [
7
+ "about",
8
+ "join",
9
+ "search",
10
+ "topic",
11
+ "watch",
12
+ "notifications",
13
+ "settings",
14
+ "submit",
15
+ "shop",
16
+ "core-membership",
17
+ "team",
18
+ "developers"
19
+ ];
20
+ const deviantartHandler = {
21
+ match: (url) => {
22
+ return isHostOf(url, hosts);
23
+ },
24
+ resolve: (url) => {
25
+ const { pathname } = new URL(url);
26
+ const tagMatch = pathname.match(/^\/tag\/([^/]+)/);
27
+ if (tagMatch?.[1]) {
28
+ const tag = tagMatch[1];
29
+ return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(`tag:${tag}`)}`];
30
+ }
31
+ const favMatch = pathname.match(/^\/([a-zA-Z0-9_-]+)\/favourites\/?$/);
32
+ if (favMatch?.[1]) {
33
+ const username = favMatch[1];
34
+ if (!isAnyOf(username, excludedPaths)) return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(`favby:${username}`)}`];
35
+ }
36
+ const folderMatch = pathname.match(/^\/([a-zA-Z0-9_-]+)\/gallery\/(\d+)(?:\/|$)/);
37
+ if (folderMatch?.[1] && folderMatch?.[2]) {
38
+ const username = folderMatch[1];
39
+ const folderId = folderMatch[2];
40
+ if (!isAnyOf(username, excludedPaths)) return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(`gallery:${username}/${folderId}`)}`];
41
+ }
42
+ const username = pathname.match(/^\/([a-zA-Z0-9_-]+)(?:\/gallery(?:\/all)?)?(?:\/|$)/)?.[1];
43
+ if (!username || isAnyOf(username, excludedPaths)) return [];
44
+ const query = `by:${username} sort:time meta:all`;
45
+ return [`${feedBaseUrl}?type=deviation&q=${encodeURIComponent(query)}`];
46
+ }
47
+ };
48
+
49
+ //#endregion
50
+ export { deviantartHandler };
@@ -0,0 +1,44 @@
1
+ const require_utils = require('../../../common/utils.cjs');
2
+
3
+ //#region src/feeds/platform/handlers/devto.ts
4
+ const hosts = ["dev.to", "www.dev.to"];
5
+ const userPathRegex = /^\/([a-zA-Z0-9_]+)\/?$/;
6
+ const tagPathRegex = /^\/t\/([^/]+)/;
7
+ const excludedPaths = [
8
+ "tag",
9
+ "tags",
10
+ "search",
11
+ "top",
12
+ "latest",
13
+ "about",
14
+ "contact",
15
+ "privacy",
16
+ "terms",
17
+ "code-of-conduct",
18
+ "faq",
19
+ "enter",
20
+ "settings",
21
+ "signout-confirm",
22
+ "notifications",
23
+ "reading-list",
24
+ "dashboard"
25
+ ];
26
+ const devtoHandler = {
27
+ match: (url) => {
28
+ return require_utils.isHostOf(url, hosts);
29
+ },
30
+ resolve: (url) => {
31
+ const { pathname } = new URL(url);
32
+ const userMatch = pathname.match(userPathRegex);
33
+ if (userMatch?.[1]) {
34
+ const username = userMatch[1];
35
+ if (!require_utils.isAnyOf(username, excludedPaths)) return [`https://dev.to/feed/${username}`];
36
+ }
37
+ const tagMatch = pathname.match(tagPathRegex);
38
+ if (tagMatch?.[1]) return [`https://dev.to/feed/tag/${tagMatch[1]}`];
39
+ return [];
40
+ }
41
+ };
42
+
43
+ //#endregion
44
+ exports.devtoHandler = devtoHandler;
@@ -0,0 +1,44 @@
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
+
3
+ //#region src/feeds/platform/handlers/devto.ts
4
+ const hosts = ["dev.to", "www.dev.to"];
5
+ const userPathRegex = /^\/([a-zA-Z0-9_]+)\/?$/;
6
+ const tagPathRegex = /^\/t\/([^/]+)/;
7
+ const excludedPaths = [
8
+ "tag",
9
+ "tags",
10
+ "search",
11
+ "top",
12
+ "latest",
13
+ "about",
14
+ "contact",
15
+ "privacy",
16
+ "terms",
17
+ "code-of-conduct",
18
+ "faq",
19
+ "enter",
20
+ "settings",
21
+ "signout-confirm",
22
+ "notifications",
23
+ "reading-list",
24
+ "dashboard"
25
+ ];
26
+ const devtoHandler = {
27
+ match: (url) => {
28
+ return isHostOf(url, hosts);
29
+ },
30
+ resolve: (url) => {
31
+ const { pathname } = new URL(url);
32
+ const userMatch = pathname.match(userPathRegex);
33
+ if (userMatch?.[1]) {
34
+ const username = userMatch[1];
35
+ if (!isAnyOf(username, excludedPaths)) return [`https://dev.to/feed/${username}`];
36
+ }
37
+ const tagMatch = pathname.match(tagPathRegex);
38
+ if (tagMatch?.[1]) return [`https://dev.to/feed/tag/${tagMatch[1]}`];
39
+ return [];
40
+ }
41
+ };
42
+
43
+ //#endregion
44
+ export { devtoHandler };
@@ -68,13 +68,19 @@ const githubHandler = {
68
68
  uris.push(`https://github.com/${owner}/${repo}/releases.atom`);
69
69
  uris.push(`https://github.com/${owner}/${repo}/commits.atom`);
70
70
  uris.push(`https://github.com/${owner}/${repo}/tags.atom`);
71
- if (pathname.includes("/wiki")) uris.push(`https://github.com/${owner}/${repo}/wiki.atom`);
72
- if (pathname.includes("/discussions")) uris.push(`https://github.com/${owner}/${repo}/discussions.atom`);
73
- const branchMatch = pathname.match(/^\/[^/]+\/[^/]+\/tree\/([^/]+)/);
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
74
  if (branchMatch?.[1]) {
75
75
  const branch = branchMatch[1];
76
76
  uris.push(`https://github.com/${owner}/${repo}/commits/${branch}.atom`);
77
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
+ }
78
84
  return uris;
79
85
  }
80
86
  };
@@ -68,13 +68,19 @@ const githubHandler = {
68
68
  uris.push(`https://github.com/${owner}/${repo}/releases.atom`);
69
69
  uris.push(`https://github.com/${owner}/${repo}/commits.atom`);
70
70
  uris.push(`https://github.com/${owner}/${repo}/tags.atom`);
71
- if (pathname.includes("/wiki")) uris.push(`https://github.com/${owner}/${repo}/wiki.atom`);
72
- if (pathname.includes("/discussions")) uris.push(`https://github.com/${owner}/${repo}/discussions.atom`);
73
- const branchMatch = pathname.match(/^\/[^/]+\/[^/]+\/tree\/([^/]+)/);
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
74
  if (branchMatch?.[1]) {
75
75
  const branch = branchMatch[1];
76
76
  uris.push(`https://github.com/${owner}/${repo}/commits/${branch}.atom`);
77
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
+ }
78
84
  return uris;
79
85
  }
80
86
  };
@@ -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 };
@@ -2,6 +2,29 @@ const require_utils = require('../../../common/utils.cjs');
2
2
 
3
3
  //#region src/feeds/platform/handlers/gitlab.ts
4
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
+ ];
5
28
  const gitlabHandler = {
6
29
  match: (url) => {
7
30
  return require_utils.isHostOf(url, hosts);
@@ -9,8 +32,19 @@ const gitlabHandler = {
9
32
  resolve: (url) => {
10
33
  const { origin, pathname } = new URL(url);
11
34
  const pathSegments = pathname.split("/").filter(Boolean);
12
- if (pathSegments.length === 1) return [`${origin}/${pathSegments[0]}.atom`];
13
- if (pathSegments.length >= 2) return [`${origin}/${pathSegments[0]}/${pathSegments[1]}.atom`];
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
+ }
14
48
  return [];
15
49
  }
16
50
  };
@@ -1,7 +1,30 @@
1
- import { isHostOf } from "../../../common/utils.js";
1
+ import { isAnyOf, isHostOf } from "../../../common/utils.js";
2
2
 
3
3
  //#region src/feeds/platform/handlers/gitlab.ts
4
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
+ ];
5
28
  const gitlabHandler = {
6
29
  match: (url) => {
7
30
  return isHostOf(url, hosts);
@@ -9,8 +32,19 @@ const gitlabHandler = {
9
32
  resolve: (url) => {
10
33
  const { origin, pathname } = new URL(url);
11
34
  const pathSegments = pathname.split("/").filter(Boolean);
12
- if (pathSegments.length === 1) return [`${origin}/${pathSegments[0]}.atom`];
13
- if (pathSegments.length >= 2) return [`${origin}/${pathSegments[0]}/${pathSegments[1]}.atom`];
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
+ }
14
48
  return [];
15
49
  }
16
50
  };
@@ -4,16 +4,13 @@ const require_utils = require('../../../common/utils.cjs');
4
4
  const hosts = ["kickstarter.com", "www.kickstarter.com"];
5
5
  const kickstarterHandler = {
6
6
  match: (url) => {
7
- if (!require_utils.isHostOf(url, hosts)) return false;
8
- const { pathname } = new URL(url);
9
- const pathSegments = pathname.split("/").filter(Boolean);
10
- return pathSegments.length >= 3 && pathSegments[0] === "projects";
7
+ return require_utils.isHostOf(url, hosts);
11
8
  },
12
9
  resolve: (url) => {
13
- const { origin, pathname } = new URL(url);
10
+ const { pathname } = new URL(url);
14
11
  const pathSegments = pathname.split("/").filter(Boolean);
15
- if (pathSegments.length >= 3 && pathSegments[0] === "projects") return [`${origin}/projects/${pathSegments[1]}/${pathSegments[2]}/posts.atom`];
16
- return [];
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"];
17
14
  }
18
15
  };
19
16
 
@@ -4,16 +4,13 @@ import { isHostOf } from "../../../common/utils.js";
4
4
  const hosts = ["kickstarter.com", "www.kickstarter.com"];
5
5
  const kickstarterHandler = {
6
6
  match: (url) => {
7
- if (!isHostOf(url, hosts)) return false;
8
- const { pathname } = new URL(url);
9
- const pathSegments = pathname.split("/").filter(Boolean);
10
- return pathSegments.length >= 3 && pathSegments[0] === "projects";
7
+ return isHostOf(url, hosts);
11
8
  },
12
9
  resolve: (url) => {
13
- const { origin, pathname } = new URL(url);
10
+ const { pathname } = new URL(url);
14
11
  const pathSegments = pathname.split("/").filter(Boolean);
15
- if (pathSegments.length >= 3 && pathSegments[0] === "projects") return [`${origin}/projects/${pathSegments[1]}/${pathSegments[2]}/posts.atom`];
16
- return [];
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"];
17
14
  }
18
15
  };
19
16
 
@@ -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;