feedscout 2.0.0-next.2 → 2.0.0-rc.2

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 (190) hide show
  1. package/README.md +1 -1
  2. package/dist/blogrolls.d.ts +4 -4
  3. package/dist/blogrolls.js +3 -3
  4. package/dist/favicons.d.ts +3 -3
  5. package/dist/favicons.js +2 -2
  6. package/dist/feeds.d.ts +4 -4
  7. package/dist/feeds.js +3 -3
  8. package/dist/hubs.d.ts +1 -1
  9. package/dist/index.d.ts +7 -7
  10. package/dist/index.js +6 -6
  11. package/dist/methods.d.ts +7 -7
  12. package/dist/methods.js +7 -7
  13. package/dist/node_modules/trousse/dist/arrays.js +9 -0
  14. package/dist/node_modules/trousse/dist/is.js +19 -0
  15. package/dist/node_modules/trousse/dist/matching.js +37 -0
  16. package/dist/node_modules/trousse/dist/urls.js +23 -0
  17. package/dist/{blogrolls → src/blogrolls}/defaults.d.ts +1 -2
  18. package/dist/{blogrolls → src/blogrolls}/defaults.js +19 -11
  19. package/dist/{blogrolls → src/blogrolls}/extractors.js +3 -2
  20. package/dist/{common → src/common}/discover/defaults.js +1 -3
  21. package/dist/{common → src/common}/discover/index.js +23 -10
  22. package/dist/{common → src/common}/discover/utils.js +10 -3
  23. package/dist/src/common/locales.js +337 -0
  24. package/dist/{common → src/common}/types.d.ts +9 -1
  25. package/dist/{common → src/common}/uris/feed/index.js +1 -1
  26. package/dist/src/common/uris/guess/index.js +16 -0
  27. package/dist/{common → src/common}/uris/guess/types.d.ts +3 -0
  28. package/dist/{common → src/common}/uris/guess/utils.d.ts +2 -1
  29. package/dist/src/common/uris/guess/utils.js +83 -0
  30. package/dist/src/common/uris/headers/index.js +14 -0
  31. package/dist/{common → src/common}/uris/html/handlers.js +18 -1
  32. package/dist/{common → src/common}/uris/html/index.js +17 -1
  33. package/dist/src/common/uris/html/types.d.ts +14 -0
  34. package/dist/src/common/utils.js +51 -0
  35. package/dist/{favicons → src/favicons}/defaults.js +1 -1
  36. package/dist/{favicons → src/favicons}/extractors.js +3 -8
  37. package/dist/{favicons → src/favicons}/platform/handlers/bluesky.js +3 -2
  38. package/dist/{favicons → src/favicons}/platform/handlers/codeberg.js +2 -1
  39. package/dist/{favicons → src/favicons}/platform/handlers/deviantart.js +2 -1
  40. package/dist/{favicons → src/favicons}/platform/handlers/devto.js +4 -2
  41. package/dist/{favicons → src/favicons}/platform/handlers/github.js +2 -1
  42. package/dist/{favicons → src/favicons}/platform/handlers/githubGist.js +2 -1
  43. package/dist/{favicons → src/favicons}/platform/handlers/gitlab.js +4 -2
  44. package/dist/{favicons → src/favicons}/platform/handlers/lobsters.js +1 -1
  45. package/dist/{favicons → src/favicons}/platform/handlers/mastodon.js +2 -1
  46. package/dist/{favicons → src/favicons}/platform/handlers/reddit.js +3 -2
  47. package/dist/{favicons → src/favicons}/platform/handlers/sourceforge.js +1 -1
  48. package/dist/{favicons → src/favicons}/platform/handlers/tumblr.js +1 -1
  49. package/dist/{favicons → src/favicons}/utils.js +1 -4
  50. package/dist/{feeds → src/feeds}/defaults.d.ts +6 -3
  51. package/dist/src/feeds/defaults.js +300 -0
  52. package/dist/{feeds → src/feeds}/extractors.js +3 -2
  53. package/dist/src/feeds/platform/handlers/acast.js +28 -0
  54. package/dist/src/feeds/platform/handlers/ameblo.js +38 -0
  55. package/dist/{feeds → src/feeds}/platform/handlers/applePodcasts.js +3 -2
  56. package/dist/src/feeds/platform/handlers/arena.js +44 -0
  57. package/dist/src/feeds/platform/handlers/artstation.js +54 -0
  58. package/dist/src/feeds/platform/handlers/audioboom.js +24 -0
  59. package/dist/src/feeds/platform/handlers/bearblog.js +46 -0
  60. package/dist/{feeds → src/feeds}/platform/handlers/behance.js +10 -1
  61. package/dist/src/feeds/platform/handlers/blogspot.js +72 -0
  62. package/dist/{feeds → src/feeds}/platform/handlers/bluesky.js +2 -1
  63. package/dist/src/feeds/platform/handlers/bookwyrm.js +48 -0
  64. package/dist/src/feeds/platform/handlers/buttondown.js +45 -0
  65. package/dist/src/feeds/platform/handlers/buzzsprout.js +23 -0
  66. package/dist/{feeds → src/feeds}/platform/handlers/codeberg.js +8 -6
  67. package/dist/{feeds → src/feeds}/platform/handlers/csdn.js +2 -1
  68. package/dist/{feeds → src/feeds}/platform/handlers/dailymotion.js +19 -1
  69. package/dist/{feeds → src/feeds}/platform/handlers/deviantart.js +28 -7
  70. package/dist/{feeds → src/feeds}/platform/handlers/devto.js +11 -1
  71. package/dist/src/feeds/platform/handlers/discourse.js +66 -0
  72. package/dist/{feeds → src/feeds}/platform/handlers/douban.js +2 -1
  73. package/dist/src/feeds/platform/handlers/dreamwidth.js +49 -0
  74. package/dist/src/feeds/platform/handlers/exblog.js +36 -0
  75. package/dist/src/feeds/platform/handlers/fireside.js +25 -0
  76. package/dist/src/feeds/platform/handlers/friendica.js +44 -0
  77. package/dist/src/feeds/platform/handlers/ghost.js +31 -0
  78. package/dist/{feeds → src/feeds}/platform/handlers/github.js +9 -1
  79. package/dist/{feeds → src/feeds}/platform/handlers/githubGist.js +19 -6
  80. package/dist/{feeds → src/feeds}/platform/handlers/gitlab.js +34 -14
  81. package/dist/{feeds → src/feeds}/platform/handlers/goodreads.js +20 -9
  82. package/dist/src/feeds/platform/handlers/hackernews.js +22 -0
  83. package/dist/{feeds → src/feeds}/platform/handlers/hashnode.js +3 -2
  84. package/dist/{feeds → src/feeds}/platform/handlers/hatenablog.js +6 -2
  85. package/dist/src/feeds/platform/handlers/hearthis.js +34 -0
  86. package/dist/src/feeds/platform/handlers/heyWorld.js +19 -0
  87. package/dist/src/feeds/platform/handlers/insanejournal.js +70 -0
  88. package/dist/{feeds → src/feeds}/platform/handlers/itchio.js +27 -2
  89. package/dist/{feeds → src/feeds}/platform/handlers/kickstarter.js +2 -1
  90. package/dist/src/feeds/platform/handlers/lemmy.js +88 -0
  91. package/dist/{feeds → src/feeds}/platform/handlers/letterboxd.js +7 -1
  92. package/dist/src/feeds/platform/handlers/libsyn.js +26 -0
  93. package/dist/src/feeds/platform/handlers/listed.js +21 -0
  94. package/dist/src/feeds/platform/handlers/livejournal.js +69 -0
  95. package/dist/{feeds → src/feeds}/platform/handlers/lobsters.js +2 -1
  96. package/dist/{feeds → src/feeds}/platform/handlers/mastodon.js +32 -0
  97. package/dist/src/feeds/platform/handlers/mataroa.js +17 -0
  98. package/dist/{feeds → src/feeds}/platform/handlers/medium.js +5 -3
  99. package/dist/src/feeds/platform/handlers/microblog.js +56 -0
  100. package/dist/src/feeds/platform/handlers/misskey.js +40 -0
  101. package/dist/src/feeds/platform/handlers/myanimelist.js +44 -0
  102. package/dist/src/feeds/platform/handlers/naverBlog.js +22 -0
  103. package/dist/src/feeds/platform/handlers/nebula.js +70 -0
  104. package/dist/src/feeds/platform/handlers/note.js +55 -0
  105. package/dist/src/feeds/platform/handlers/observable.js +35 -0
  106. package/dist/src/feeds/platform/handlers/odysee.js +21 -0
  107. package/dist/src/feeds/platform/handlers/pagecord.js +17 -0
  108. package/dist/{feeds → src/feeds}/platform/handlers/paragraph.js +3 -3
  109. package/dist/src/feeds/platform/handlers/pika.js +36 -0
  110. package/dist/{feeds → src/feeds}/platform/handlers/pinterest.js +16 -1
  111. package/dist/src/feeds/platform/handlers/pixelfed.js +46 -0
  112. package/dist/src/feeds/platform/handlers/pleroma.js +34 -0
  113. package/dist/src/feeds/platform/handlers/podbean.js +30 -0
  114. package/dist/src/feeds/platform/handlers/podigee.js +30 -0
  115. package/dist/src/feeds/platform/handlers/posthaven.js +25 -0
  116. package/dist/{feeds → src/feeds}/platform/handlers/producthunt.js +2 -1
  117. package/dist/src/feeds/platform/handlers/prose.js +27 -0
  118. package/dist/src/feeds/platform/handlers/qiita.js +60 -0
  119. package/dist/src/feeds/platform/handlers/reddit.js +150 -0
  120. package/dist/src/feeds/platform/handlers/rssCom.js +21 -0
  121. package/dist/src/feeds/platform/handlers/seesaa.js +23 -0
  122. package/dist/{feeds → src/feeds}/platform/handlers/soundcloud.js +3 -1
  123. package/dist/src/feeds/platform/handlers/sourceforge.js +53 -0
  124. package/dist/src/feeds/platform/handlers/spreaker.js +22 -0
  125. package/dist/{feeds → src/feeds}/platform/handlers/stackExchange.js +28 -3
  126. package/dist/{feeds → src/feeds}/platform/handlers/steam.js +9 -1
  127. package/dist/{feeds → src/feeds}/platform/handlers/substack.js +2 -1
  128. package/dist/src/feeds/platform/handlers/tildes.js +42 -0
  129. package/dist/src/feeds/platform/handlers/tistory.js +17 -0
  130. package/dist/src/feeds/platform/handlers/transistor.js +30 -0
  131. package/dist/{feeds → src/feeds}/platform/handlers/tumblr.js +2 -1
  132. package/dist/{feeds → src/feeds}/platform/handlers/v2ex.js +2 -1
  133. package/dist/src/feeds/platform/handlers/velog.js +25 -0
  134. package/dist/{feeds → src/feeds}/platform/handlers/vimeo.js +9 -1
  135. package/dist/src/feeds/platform/handlers/weblogLol.js +27 -0
  136. package/dist/src/feeds/platform/handlers/weebly.js +26 -0
  137. package/dist/src/feeds/platform/handlers/wordpress.js +210 -0
  138. package/dist/{feeds → src/feeds}/platform/handlers/wpengine.js +1 -1
  139. package/dist/src/feeds/platform/handlers/writeas.js +53 -0
  140. package/dist/{feeds → src/feeds}/platform/handlers/ximalaya.js +3 -2
  141. package/dist/{feeds → src/feeds}/platform/handlers/youtube.js +6 -2
  142. package/dist/src/feeds/platform/handlers/zenn.js +56 -0
  143. package/package.json +10 -11
  144. package/dist/common/locales.js +0 -133
  145. package/dist/common/uris/guess/index.js +0 -8
  146. package/dist/common/uris/guess/utils.js +0 -40
  147. package/dist/common/uris/headers/index.js +0 -26
  148. package/dist/common/uris/html/types.d.ts +0 -12
  149. package/dist/common/utils.d.ts +0 -10
  150. package/dist/common/utils.js +0 -79
  151. package/dist/feeds/defaults.js +0 -168
  152. package/dist/feeds/platform/handlers/blogspot.js +0 -36
  153. package/dist/feeds/platform/handlers/lemmy.js +0 -46
  154. package/dist/feeds/platform/handlers/reddit.js +0 -74
  155. package/dist/feeds/platform/handlers/sourceforge.js +0 -19
  156. package/dist/feeds/platform/handlers/wordpress.js +0 -64
  157. package/dist/utils.d.ts +0 -2
  158. package/dist/utils.js +0 -2
  159. /package/dist/{blogrolls → src/blogrolls}/extractors.d.ts +0 -0
  160. /package/dist/{blogrolls → src/blogrolls}/index.d.ts +0 -0
  161. /package/dist/{blogrolls → src/blogrolls}/index.js +0 -0
  162. /package/dist/{blogrolls → src/blogrolls}/types.d.ts +0 -0
  163. /package/dist/{common → src/common}/discover/defaults.d.ts +0 -0
  164. /package/dist/{common → src/common}/discover/utils.d.ts +0 -0
  165. /package/dist/{common → src/common}/types.js +0 -0
  166. /package/dist/{common → src/common}/uris/feed/index.d.ts +0 -0
  167. /package/dist/{common → src/common}/uris/feed/types.d.ts +0 -0
  168. /package/dist/{common → src/common}/uris/guess/index.d.ts +0 -0
  169. /package/dist/{common → src/common}/uris/headers/index.d.ts +0 -0
  170. /package/dist/{common → src/common}/uris/headers/types.d.ts +0 -0
  171. /package/dist/{common → src/common}/uris/html/index.d.ts +0 -0
  172. /package/dist/{common → src/common}/uris/index.js +0 -0
  173. /package/dist/{common → src/common}/uris/platform/index.d.ts +0 -0
  174. /package/dist/{common → src/common}/uris/platform/index.js +0 -0
  175. /package/dist/{common → src/common}/uris/platform/types.d.ts +0 -0
  176. /package/dist/{favicons → src/favicons}/defaults.d.ts +0 -0
  177. /package/dist/{favicons → src/favicons}/extractors.d.ts +0 -0
  178. /package/dist/{favicons → src/favicons}/index.d.ts +0 -0
  179. /package/dist/{favicons → src/favicons}/index.js +0 -0
  180. /package/dist/{favicons → src/favicons}/types.d.ts +0 -0
  181. /package/dist/{feeds → src/feeds}/extractors.d.ts +0 -0
  182. /package/dist/{feeds → src/feeds}/index.d.ts +0 -0
  183. /package/dist/{feeds → src/feeds}/index.js +0 -0
  184. /package/dist/{feeds → src/feeds}/types.d.ts +0 -0
  185. /package/dist/{hubs → src/hubs}/discover/index.d.ts +0 -0
  186. /package/dist/{hubs → src/hubs}/discover/index.js +0 -0
  187. /package/dist/{hubs → src/hubs}/discover/types.d.ts +0 -0
  188. /package/dist/{hubs → src/hubs}/feed/index.js +0 -0
  189. /package/dist/{hubs → src/hubs}/headers/index.js +0 -0
  190. /package/dist/{hubs → src/hubs}/html/index.js +0 -0
@@ -0,0 +1,36 @@
1
+ import { isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
3
+ //#region src/feeds/platform/handlers/exblog.ts
4
+ const categoryRegex = /^\/i(\d+)/;
5
+ const exblogHandler = {
6
+ match: (url) => {
7
+ return isSubdomainOf(url, "exblog.jp");
8
+ },
9
+ resolve: (url) => {
10
+ const { origin, pathname } = new URL(url);
11
+ const uris = [];
12
+ const categoryMatch = pathname.match(categoryRegex);
13
+ if (categoryMatch?.[1]) {
14
+ const categoryId = categoryMatch[1];
15
+ uris.push({
16
+ uri: `${origin}/i${categoryId}/index.xml`,
17
+ hint: composeHint("exblog:category-rss")
18
+ });
19
+ uris.push({
20
+ uri: `${origin}/i${categoryId}/atom.xml`,
21
+ hint: composeHint("exblog:category-atom")
22
+ });
23
+ }
24
+ uris.push({
25
+ uri: `${origin}/index.xml`,
26
+ hint: composeHint("exblog:posts-rss")
27
+ });
28
+ uris.push({
29
+ uri: `${origin}/atom.xml`,
30
+ hint: composeHint("exblog:posts-atom")
31
+ });
32
+ return uris;
33
+ }
34
+ };
35
+ //#endregion
36
+ export { exblogHandler };
@@ -0,0 +1,25 @@
1
+ import { isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
3
+ //#region src/feeds/platform/handlers/fireside.ts
4
+ const domainSuffixRegex = /\.fireside\.fm$/i;
5
+ const firesideHandler = {
6
+ match: (url) => {
7
+ return isSubdomainOf(url, "fireside.fm");
8
+ },
9
+ resolve: (url) => {
10
+ const { hostname } = new URL(url);
11
+ const slug = hostname.replace(domainSuffixRegex, "");
12
+ const uris = [];
13
+ uris.push({
14
+ uri: `https://feeds.fireside.fm/${slug}/rss`,
15
+ hint: composeHint("fireside:podcast-rss")
16
+ });
17
+ uris.push({
18
+ uri: `https://${slug}.fireside.fm/json`,
19
+ hint: composeHint("fireside:podcast-json")
20
+ });
21
+ return uris;
22
+ }
23
+ };
24
+ //#endregion
25
+ export { firesideHandler };
@@ -0,0 +1,44 @@
1
+ import { composeHint, hasMetaContent } from "../../../common/utils.js";
2
+ //#region src/feeds/platform/handlers/friendica.ts
3
+ const profileRegex = /^\/profile\/([^/]+)/;
4
+ const isFriendicaHtml = (content) => {
5
+ return hasMetaContent(content, "generator", "Friendica");
6
+ };
7
+ const friendicaHandler = {
8
+ match: (url, content) => {
9
+ try {
10
+ if (!content || !isFriendicaHtml(content)) return false;
11
+ const { pathname } = new URL(url);
12
+ return profileRegex.test(pathname);
13
+ } catch {}
14
+ return false;
15
+ },
16
+ resolve: (url) => {
17
+ try {
18
+ const { origin, pathname } = new URL(url);
19
+ const match = pathname.match(profileRegex);
20
+ if (!match?.[1]) return [];
21
+ return [
22
+ {
23
+ uri: `${origin}/feed/${match[1]}`,
24
+ hint: composeHint("friendica:posts")
25
+ },
26
+ {
27
+ uri: `${origin}/feed/${match[1]}/comments`,
28
+ hint: composeHint("friendica:comments")
29
+ },
30
+ {
31
+ uri: `${origin}/feed/${match[1]}/replies`,
32
+ hint: composeHint("friendica:replies")
33
+ },
34
+ {
35
+ uri: `${origin}/feed/${match[1]}/activity`,
36
+ hint: composeHint("friendica:activity")
37
+ }
38
+ ];
39
+ } catch {}
40
+ return [];
41
+ }
42
+ };
43
+ //#endregion
44
+ export { friendicaHandler };
@@ -0,0 +1,31 @@
1
+ import { isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
3
+ //#region src/feeds/platform/handlers/ghost.ts
4
+ const tagRegex = /^\/tag\/([^/]+)/;
5
+ const authorRegex = /^\/author\/([^/]+)/;
6
+ const ghostHandler = {
7
+ match: (url) => {
8
+ return isSubdomainOf(url, "ghost.io");
9
+ },
10
+ resolve: (url) => {
11
+ const { origin, pathname } = new URL(url);
12
+ const uris = [];
13
+ const tagMatch = pathname.match(tagRegex);
14
+ if (tagMatch?.[1]) uris.push({
15
+ uri: `${origin}/tag/${tagMatch[1]}/rss/`,
16
+ hint: composeHint("ghost:tag")
17
+ });
18
+ const authorMatch = pathname.match(authorRegex);
19
+ if (authorMatch?.[1]) uris.push({
20
+ uri: `${origin}/author/${authorMatch[1]}/rss/`,
21
+ hint: composeHint("ghost:author")
22
+ });
23
+ uris.push({
24
+ uri: `${origin}/rss/`,
25
+ hint: composeHint("ghost:blog")
26
+ });
27
+ return uris;
28
+ }
29
+ };
30
+ //#endregion
31
+ export { ghostHandler };
@@ -1,9 +1,12 @@
1
- import { composeHint, isAnyOf, isHostOf } from "../../../common/utils.js";
1
+ import { isAnyOf } from "../../../../node_modules/trousse/dist/matching.js";
2
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
3
+ import { composeHint } from "../../../common/utils.js";
2
4
  //#region src/feeds/platform/handlers/github.ts
3
5
  const userRegex = /^\/([^/]+)\/?$/;
4
6
  const repoRegex = /^\/([^/]+)\/([^/]+)/;
5
7
  const wikiRegex = /\/wiki(\/|$)/;
6
8
  const discussionsRegex = /\/discussions(\/|$)/;
9
+ const discussionCategoryRegex = /\/discussions\/categories\/([^/]+)/;
7
10
  const branchRegex = /^\/[^/]+\/[^/]+\/tree\/([^/]+)\/?$/;
8
11
  const fileRegex = /^\/[^/]+\/[^/]+\/(?:blob|commits)\/([^/]+)\/(.+)/;
9
12
  const hosts = ["github.com", "www.github.com"];
@@ -90,6 +93,11 @@ const githubHandler = {
90
93
  uri: `https://github.com/${owner}/${repo}/discussions.atom`,
91
94
  hint: composeHint("github:discussions")
92
95
  });
96
+ const discussionCategoryMatch = pathname.match(discussionCategoryRegex);
97
+ if (discussionCategoryMatch?.[1]) uris.push({
98
+ uri: `https://github.com/${owner}/${repo}/discussions/categories/${discussionCategoryMatch[1]}.atom`,
99
+ hint: composeHint("github:discussion-category")
100
+ });
93
101
  const branchMatch = pathname.match(branchRegex);
94
102
  if (branchMatch?.[1]) {
95
103
  const branch = branchMatch[1];
@@ -1,8 +1,12 @@
1
- import { composeHint, isAnyOf, isHostOf } from "../../../common/utils.js";
1
+ import { isAnyOf } from "../../../../node_modules/trousse/dist/matching.js";
2
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
3
+ import { composeHint } from "../../../common/utils.js";
2
4
  //#region src/feeds/platform/handlers/githubGist.ts
3
5
  const gistRegex = /^\/([^/]+)\/([a-f0-9]+)/;
4
6
  const starredRegex = /^\/([^/]+)\/starred\/?$/;
7
+ const forksRegex = /^\/([^/]+)\/forks\/?$/;
5
8
  const userRegex = /^\/([^/]+)\/?$/;
9
+ const discoverRegex = /^\/discover\/?$/;
6
10
  const hosts = ["gist.github.com"];
7
11
  const excludedPaths = [
8
12
  "discover",
@@ -17,6 +21,20 @@ const githubGistHandler = {
17
21
  },
18
22
  resolve: (url) => {
19
23
  const { pathname } = new URL(url);
24
+ if (discoverRegex.test(pathname)) return [{
25
+ uri: "https://gist.github.com/discover.atom",
26
+ hint: composeHint("github-gist:discover")
27
+ }];
28
+ const starredMatch = pathname.match(starredRegex);
29
+ if (starredMatch?.[1] && !isAnyOf(starredMatch[1], excludedPaths)) return [{
30
+ uri: `https://gist.github.com/${starredMatch[1]}/starred.atom`,
31
+ hint: composeHint("github-gist:starred")
32
+ }];
33
+ const forksMatch = pathname.match(forksRegex);
34
+ if (forksMatch?.[1] && !isAnyOf(forksMatch[1], excludedPaths)) return [{
35
+ uri: `https://gist.github.com/${forksMatch[1]}/forks.atom`,
36
+ hint: composeHint("github-gist:forks")
37
+ }];
20
38
  const gistMatch = pathname.match(gistRegex);
21
39
  if (gistMatch?.[1] && gistMatch?.[2]) {
22
40
  const username = gistMatch[1];
@@ -26,11 +44,6 @@ const githubGistHandler = {
26
44
  }];
27
45
  return [];
28
46
  }
29
- const starredMatch = pathname.match(starredRegex);
30
- if (starredMatch?.[1] && !isAnyOf(starredMatch[1], excludedPaths)) return [{
31
- uri: `https://gist.github.com/${starredMatch[1]}/starred.atom`,
32
- hint: composeHint("github-gist:starred")
33
- }];
34
47
  const userMatch = pathname.match(userRegex);
35
48
  if (userMatch?.[1] && !isAnyOf(userMatch[1], excludedPaths)) return [{
36
49
  uri: `https://gist.github.com/${userMatch[1]}.atom`,
@@ -1,4 +1,6 @@
1
- import { composeHint, hasMetaContent, isAnyOf, isHostOf } from "../../../common/utils.js";
1
+ import { isAnyOf } from "../../../../node_modules/trousse/dist/matching.js";
2
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
3
+ import { composeHint, hasMetaContent } from "../../../common/utils.js";
2
4
  //#region src/feeds/platform/handlers/gitlab.ts
3
5
  const hosts = ["gitlab.com", "www.gitlab.com"];
4
6
  const excludedPaths = [
@@ -54,20 +56,38 @@ const gitlabHandler = {
54
56
  if (pathSegments.length >= 2) {
55
57
  const user = pathSegments[0];
56
58
  const repo = pathSegments[1];
57
- if (!isAnyOf(user, excludedPaths)) return [
58
- {
59
- uri: `${origin}/${user}/${repo}/-/releases.atom`,
60
- hint: composeHint("gitlab:releases")
61
- },
62
- {
63
- uri: `${origin}/${user}/${repo}/-/tags?format=atom`,
64
- hint: composeHint("gitlab:tags")
65
- },
66
- {
67
- uri: `${origin}/${user}/${repo}.atom`,
68
- hint: composeHint("gitlab:activity")
59
+ if (!isAnyOf(user, excludedPaths)) {
60
+ const repoFeeds = [
61
+ {
62
+ uri: `${origin}/${user}/${repo}/-/releases.atom`,
63
+ hint: composeHint("gitlab:releases")
64
+ },
65
+ {
66
+ uri: `${origin}/${user}/${repo}/-/tags?format=atom`,
67
+ hint: composeHint("gitlab:tags")
68
+ },
69
+ {
70
+ uri: `${origin}/${user}/${repo}/-/issues.atom`,
71
+ hint: composeHint("gitlab:issues")
72
+ },
73
+ {
74
+ uri: `${origin}/${user}/${repo}/-/merge_requests.atom`,
75
+ hint: composeHint("gitlab:merge-requests")
76
+ },
77
+ {
78
+ uri: `${origin}/${user}/${repo}.atom`,
79
+ hint: composeHint("gitlab:activity")
80
+ }
81
+ ];
82
+ if (pathSegments[2] === "-" && (pathSegments[3] === "commits" || pathSegments[3] === "tree") && pathSegments[4]) {
83
+ const branch = pathSegments[4];
84
+ repoFeeds.unshift({
85
+ uri: `${origin}/${user}/${repo}/-/commits/${branch}?format=atom`,
86
+ hint: composeHint("gitlab:branch-commits")
87
+ });
69
88
  }
70
- ];
89
+ return repoFeeds;
90
+ }
71
91
  }
72
92
  return [];
73
93
  }
@@ -1,4 +1,5 @@
1
- import { composeHint, isHostOf } from "../../../common/utils.js";
1
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
2
3
  //#region src/feeds/platform/handlers/goodreads.ts
3
4
  const hosts = ["goodreads.com", "www.goodreads.com"];
4
5
  const parseUserId = (segment) => {
@@ -10,8 +11,9 @@ const goodreadsHandler = {
10
11
  return isHostOf(url, hosts);
11
12
  },
12
13
  resolve: (url) => {
13
- const { origin, pathname } = new URL(url);
14
+ const { origin, pathname, searchParams } = new URL(url);
14
15
  const pathSegments = pathname.split("/").filter(Boolean);
16
+ const shelf = searchParams.get("shelf");
15
17
  if (pathSegments[0] === "user" && pathSegments[1] === "show" && pathSegments[2]) {
16
18
  const userId = parseUserId(pathSegments[2]);
17
19
  if (userId) return [{
@@ -24,13 +26,22 @@ const goodreadsHandler = {
24
26
  }
25
27
  if (pathSegments[0] === "review" && pathSegments[1] === "list" && pathSegments[2]) {
26
28
  const userId = parseUserId(pathSegments[2]);
27
- if (userId) return [{
28
- uri: `${origin}/review/list_rss/${userId}`,
29
- hint: composeHint("goodreads:reviews")
30
- }, {
31
- uri: `${origin}/user/updates_rss/${userId}`,
32
- hint: composeHint("goodreads:updates")
33
- }];
29
+ if (userId) {
30
+ const uris = [];
31
+ if (shelf) uris.push({
32
+ uri: `${origin}/review/list_rss/${userId}?shelf=${encodeURIComponent(shelf)}`,
33
+ hint: composeHint("goodreads:shelf")
34
+ });
35
+ uris.push({
36
+ uri: `${origin}/review/list_rss/${userId}`,
37
+ hint: composeHint("goodreads:reviews")
38
+ });
39
+ uris.push({
40
+ uri: `${origin}/user/updates_rss/${userId}`,
41
+ hint: composeHint("goodreads:updates")
42
+ });
43
+ return uris;
44
+ }
34
45
  }
35
46
  return [];
36
47
  }
@@ -0,0 +1,22 @@
1
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
3
+ //#region src/feeds/platform/handlers/hackernews.ts
4
+ const hosts = ["news.ycombinator.com"];
5
+ const hackernewsHandler = {
6
+ match: (url) => {
7
+ return isHostOf(url, hosts);
8
+ },
9
+ resolve: (url) => {
10
+ const { pathname } = new URL(url);
11
+ if (pathname === "/show" || pathname === "/shownew") return [{
12
+ uri: "https://news.ycombinator.com/showrss",
13
+ hint: composeHint("hackernews:show")
14
+ }];
15
+ return [{
16
+ uri: "https://news.ycombinator.com/rss",
17
+ hint: composeHint("hackernews:front")
18
+ }];
19
+ }
20
+ };
21
+ //#endregion
22
+ export { hackernewsHandler };
@@ -1,8 +1,9 @@
1
- import { composeHint, isSubdomainOf } from "../../../common/utils.js";
1
+ import { isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
2
3
  //#region src/feeds/platform/handlers/hashnode.ts
3
4
  const hashnodeHandler = {
4
5
  match: (url) => {
5
- return isSubdomainOf(url, "hashnode.dev");
6
+ return isSubdomainOf(url, ["hashnode.dev", "hashnode.com"]);
6
7
  },
7
8
  resolve: (url) => {
8
9
  const { origin } = new URL(url);
@@ -1,9 +1,13 @@
1
- import { composeHint, isSubdomainOf } from "../../../common/utils.js";
1
+ import { isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
2
3
  //#region src/feeds/platform/handlers/hatenablog.ts
3
4
  const domains = [
4
5
  "hatenablog.com",
5
6
  "hatenablog.jp",
6
- "hateblo.jp"
7
+ "hateblo.jp",
8
+ "hatenadiary.com",
9
+ "hatenadiary.jp",
10
+ "hatenadiary.org"
7
11
  ];
8
12
  const categoryRegex = /^\/archive\/category\/([^/]+)/;
9
13
  const authorRegex = /^\/archive\/author\/([^/]+)/;
@@ -0,0 +1,34 @@
1
+ import { isAnyOf } from "../../../../node_modules/trousse/dist/matching.js";
2
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
3
+ import { composeHint } from "../../../common/utils.js";
4
+ //#region src/feeds/platform/handlers/hearthis.ts
5
+ const hosts = ["hearthis.at", "www.hearthis.at"];
6
+ const excludedPaths = [
7
+ "about",
8
+ "api",
9
+ "feed",
10
+ "login",
11
+ "privacy",
12
+ "search",
13
+ "set",
14
+ "signup",
15
+ "terms"
16
+ ];
17
+ const hearthisHandler = {
18
+ match: (url) => {
19
+ return isHostOf(url, hosts);
20
+ },
21
+ resolve: (url) => {
22
+ const { pathname } = new URL(url);
23
+ const pathSegments = pathname.split("/").filter(Boolean);
24
+ if (pathSegments.length === 0) return [];
25
+ const username = pathSegments[0];
26
+ if (isAnyOf(username, excludedPaths)) return [];
27
+ return [{
28
+ uri: `https://hearthis.at/${username}/podcast/`,
29
+ hint: composeHint("hearthis:tracks")
30
+ }];
31
+ }
32
+ };
33
+ //#endregion
34
+ export { hearthisHandler };
@@ -0,0 +1,19 @@
1
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
3
+ //#region src/feeds/platform/handlers/heyWorld.ts
4
+ const heyWorldHandler = {
5
+ match: (url) => {
6
+ return isHostOf(url, "world.hey.com");
7
+ },
8
+ resolve: (url) => {
9
+ const { pathname } = new URL(url);
10
+ const pathSegments = pathname.split("/").filter(Boolean);
11
+ if (pathSegments.length === 0) return [];
12
+ return [{
13
+ uri: `https://world.hey.com/${pathSegments[0]}/feed.atom`,
14
+ hint: composeHint("hey-world:blog")
15
+ }];
16
+ }
17
+ };
18
+ //#endregion
19
+ export { heyWorldHandler };
@@ -0,0 +1,70 @@
1
+ import { isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
3
+ //#region src/feeds/platform/handlers/insanejournal.ts
4
+ const wwwUsersPathRegex = /^\/(?:users\/|~)([^/]+)/;
5
+ const wwwAsylumPathRegex = /^\/(?:asylum|community)\/([^/]+)/;
6
+ const firstSegmentRegex = /^\/([^/]+)/;
7
+ const tagRegex = /^\/tag\/([^/]+)/;
8
+ const insanejournalHandler = {
9
+ match: (url) => {
10
+ if (!isSubdomainOf(url, "insanejournal.com")) return false;
11
+ const { hostname, pathname } = new URL(url);
12
+ const lower = hostname.toLowerCase();
13
+ if (lower === "www.insanejournal.com" || lower === "insanejournal.com") return wwwUsersPathRegex.test(pathname) || wwwAsylumPathRegex.test(pathname);
14
+ if (lower === "asylums.insanejournal.com" || lower === "feeds.insanejournal.com") return firstSegmentRegex.test(pathname);
15
+ return true;
16
+ },
17
+ resolve: (url) => {
18
+ const { origin, hostname, pathname } = new URL(url);
19
+ const lowerHostname = hostname.toLowerCase();
20
+ const uris = [];
21
+ let feedOrigin = origin;
22
+ let feedPathPrefix = "";
23
+ if (lowerHostname === "www.insanejournal.com" || lowerHostname === "insanejournal.com") {
24
+ const userMatch = pathname.match(wwwUsersPathRegex);
25
+ if (userMatch?.[1]) feedOrigin = `https://${userMatch[1]}.insanejournal.com`;
26
+ else {
27
+ const asylumMatch = pathname.match(wwwAsylumPathRegex);
28
+ if (asylumMatch?.[1]) {
29
+ feedOrigin = "https://asylums.insanejournal.com";
30
+ feedPathPrefix = `/${asylumMatch[1]}`;
31
+ } else return uris;
32
+ }
33
+ } else if (lowerHostname === "asylums.insanejournal.com") {
34
+ const segMatch = pathname.match(firstSegmentRegex);
35
+ if (segMatch?.[1]) feedPathPrefix = `/${segMatch[1]}`;
36
+ else return uris;
37
+ } else if (lowerHostname === "feeds.insanejournal.com") {
38
+ const segMatch = pathname.match(firstSegmentRegex);
39
+ if (segMatch?.[1]) feedPathPrefix = `/${segMatch[1]}`;
40
+ else return uris;
41
+ }
42
+ const tagMatch = pathname.match(tagRegex);
43
+ if (tagMatch?.[1]) {
44
+ const tag = encodeURIComponent(tagMatch[1]);
45
+ uris.push({
46
+ uri: `${feedOrigin}${feedPathPrefix}/data/rss?tag=${tag}`,
47
+ hint: composeHint("insanejournal:posts-tag-rss")
48
+ });
49
+ uris.push({
50
+ uri: `${feedOrigin}${feedPathPrefix}/data/atom?tag=${tag}`,
51
+ hint: composeHint("insanejournal:posts-tag-atom")
52
+ });
53
+ }
54
+ uris.push({
55
+ uri: `${feedOrigin}${feedPathPrefix}/data/rss`,
56
+ hint: composeHint("insanejournal:posts-rss")
57
+ });
58
+ uris.push({
59
+ uri: `${feedOrigin}${feedPathPrefix}/data/atom`,
60
+ hint: composeHint("insanejournal:posts-atom")
61
+ });
62
+ uris.push({
63
+ uri: `${feedOrigin}${feedPathPrefix}/data/userpics`,
64
+ hint: composeHint("insanejournal:userpics-atom")
65
+ });
66
+ return uris;
67
+ }
68
+ };
69
+ //#endregion
70
+ export { insanejournalHandler };
@@ -1,4 +1,6 @@
1
- import { composeHint, isAnyOf, isHostOf, isSubdomainOf } from "../../../common/utils.js";
1
+ import { isAnyOf } from "../../../../node_modules/trousse/dist/matching.js";
2
+ import { isHostOf, isSubdomainOf } from "../../../../node_modules/trousse/dist/urls.js";
3
+ import { composeHint } from "../../../common/utils.js";
2
4
  //#region src/feeds/platform/handlers/itchio.ts
3
5
  const mainHosts = ["itch.io", "www.itch.io"];
4
6
  const sections = [
@@ -14,10 +16,14 @@ const sorts = [
14
16
  "newest",
15
17
  "top-rated",
16
18
  "top-sellers",
17
- "on-sale"
19
+ "on-sale",
20
+ "free"
18
21
  ];
19
22
  const byUserRegex = /^\/games\/by-([^/]+)/;
20
23
  const tagRegex = /^\/games\/tag-([^/]+)/;
24
+ const platformRegex = /^\/games\/platform-([^/.]+)/;
25
+ const genreRegex = /^\/games\/genre-([^/.]+)/;
26
+ const madeWithRegex = /^\/games\/made-with-([^/.]+)/;
21
27
  const sortRegex = /^\/games\/([^/.]+)/;
22
28
  const sectionRegex = /^\/([^/.]+)/;
23
29
  const gameRegex = /^\/([^/]+)/;
@@ -50,6 +56,21 @@ const itchioHandler = {
50
56
  uri: `https://itch.io/games/tag-${tagMatch[1]}.xml`,
51
57
  hint: composeHint("itchio:tag")
52
58
  }];
59
+ const platformMatch = pathname.match(platformRegex);
60
+ if (platformMatch?.[1]) return [{
61
+ uri: `https://itch.io/games/platform-${platformMatch[1]}.xml`,
62
+ hint: composeHint("itchio:platform")
63
+ }];
64
+ const genreMatch = pathname.match(genreRegex);
65
+ if (genreMatch?.[1]) return [{
66
+ uri: `https://itch.io/games/genre-${genreMatch[1]}.xml`,
67
+ hint: composeHint("itchio:genre")
68
+ }];
69
+ const madeWithMatch = pathname.match(madeWithRegex);
70
+ if (madeWithMatch?.[1]) return [{
71
+ uri: `https://itch.io/games/made-with-${madeWithMatch[1]}.xml`,
72
+ hint: composeHint("itchio:made-with")
73
+ }];
53
74
  const sortMatch = pathname.match(sortRegex);
54
75
  if (sortMatch?.[1] && isAnyOf(sortMatch[1], sorts)) return [{
55
76
  uri: `https://itch.io/games/${sortMatch[1]}.xml`,
@@ -81,6 +102,10 @@ const itchioHandler = {
81
102
  uri: "https://itch.io/feed/sales.xml",
82
103
  hint: composeHint("itchio:sales")
83
104
  });
105
+ uris.push({
106
+ uri: "https://itch.io/blog.rss",
107
+ hint: composeHint("itchio:blog")
108
+ });
84
109
  return uris;
85
110
  }
86
111
  };
@@ -1,4 +1,5 @@
1
- import { composeHint, isHostOf } from "../../../common/utils.js";
1
+ import { isHostOf } from "../../../../node_modules/trousse/dist/urls.js";
2
+ import { composeHint } from "../../../common/utils.js";
2
3
  //#region src/feeds/platform/handlers/kickstarter.ts
3
4
  const hosts = ["kickstarter.com", "www.kickstarter.com"];
4
5
  const kickstarterHandler = {
@@ -0,0 +1,88 @@
1
+ import { composeHint, hasMetaContent } from "../../../common/utils.js";
2
+ //#region src/feeds/platform/handlers/lemmy.ts
3
+ const lemmyPoweredByRegex = /lemmy/i;
4
+ const validSorts = /* @__PURE__ */ new Set([
5
+ "Active",
6
+ "Hot",
7
+ "New",
8
+ "Old",
9
+ "TopHour",
10
+ "TopSixHour",
11
+ "TopTwelveHour",
12
+ "TopDay",
13
+ "TopWeek",
14
+ "TopMonth",
15
+ "TopThreeMonths",
16
+ "TopSixMonths",
17
+ "TopNineMonths",
18
+ "TopYear",
19
+ "TopAll",
20
+ "Controversial",
21
+ "Scaled",
22
+ "MostComments",
23
+ "NewComments"
24
+ ]);
25
+ const numericRegex = /^\d+$/;
26
+ const getQuerySuffix = (searchParams) => {
27
+ const params = new URLSearchParams();
28
+ const sort = searchParams.get("sort");
29
+ if (sort && validSorts.has(sort)) params.set("sort", sort);
30
+ const limit = searchParams.get("limit");
31
+ if (limit && numericRegex.test(limit)) params.set("limit", limit);
32
+ const query = params.toString();
33
+ return query ? `?${query}` : "";
34
+ };
35
+ const isCommunityPath = (pathname) => {
36
+ const segments = pathname.split("/").filter(Boolean);
37
+ return segments.length >= 2 && segments[0] === "c";
38
+ };
39
+ const isUserPath = (pathname) => {
40
+ const segments = pathname.split("/").filter(Boolean);
41
+ return segments.length >= 2 && segments[0] === "u";
42
+ };
43
+ const isHomePath = (pathname) => {
44
+ return pathname === "/" || pathname === "" || pathname === "/home";
45
+ };
46
+ const isLemmyHtml = (content) => {
47
+ return hasMetaContent(content, "generator", "Lemmy");
48
+ };
49
+ const isLemmyHeaders = (headers) => {
50
+ const poweredBy = headers.get("x-powered-by") ?? "";
51
+ return lemmyPoweredByRegex.test(poweredBy);
52
+ };
53
+ const lemmyHandler = {
54
+ match: (url, content, headers) => {
55
+ try {
56
+ const { pathname } = new URL(url);
57
+ if (!isCommunityPath(pathname) && !isUserPath(pathname) && !isHomePath(pathname)) return false;
58
+ if (content && isLemmyHtml(content)) return true;
59
+ if (headers && isLemmyHeaders(headers)) return true;
60
+ } catch {}
61
+ return false;
62
+ },
63
+ resolve: (url) => {
64
+ try {
65
+ const { origin, pathname, searchParams } = new URL(url);
66
+ const segments = pathname.split("/").filter(Boolean);
67
+ const sortSuffix = getQuerySuffix(searchParams);
68
+ if (isCommunityPath(pathname) && segments[1]) return [{
69
+ uri: `${origin}/feeds/c/${segments[1]}.xml${sortSuffix}`,
70
+ hint: composeHint("lemmy:community")
71
+ }];
72
+ if (isUserPath(pathname) && segments[1]) return [{
73
+ uri: `${origin}/feeds/u/${segments[1]}.xml${sortSuffix}`,
74
+ hint: composeHint("lemmy:user")
75
+ }];
76
+ if (isHomePath(pathname)) return [{
77
+ uri: `${origin}/feeds/all.xml${sortSuffix}`,
78
+ hint: composeHint("lemmy:all")
79
+ }, {
80
+ uri: `${origin}/feeds/local.xml${sortSuffix}`,
81
+ hint: composeHint("lemmy:local")
82
+ }];
83
+ } catch {}
84
+ return [];
85
+ }
86
+ };
87
+ //#endregion
88
+ export { lemmyHandler };