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
@@ -1,133 +0,0 @@
1
- //#region src/common/locales.json
2
- var errors = {
3
- "platformMethodRequiresUrl": "Platform method requires url to be provided in input",
4
- "feedMethodRequiresContent": "Feed method requires content to be provided in input",
5
- "htmlMethodRequiresContent": "HTML method requires content to be provided in input",
6
- "headersMethodRequiresHeaders": "Headers method requires headers to be provided in input",
7
- "guessMethodRequiresUrl": "Guess method requires url to be provided in input"
8
- };
9
- var hints = {
10
- "youtube:all": "All uploads",
11
- "youtube:videos": "Videos",
12
- "youtube:shorts": "Shorts",
13
- "youtube:live": "Live streams",
14
- "youtube:popular-videos": "Popular videos",
15
- "youtube:popular-shorts": "Popular shorts",
16
- "youtube:popular-live": "Popular live streams",
17
- "youtube:member-videos": "Member videos",
18
- "youtube:member-shorts": "Member shorts",
19
- "youtube:member-live": "Member live streams",
20
- "youtube:playlist": "Playlist",
21
- "github:activity": "Activity",
22
- "github:releases": "Releases",
23
- "github:commits": "Commits",
24
- "github:tags": "Tags",
25
- "github:wiki": "Wiki",
26
- "github:discussions": "Discussions",
27
- "github:branch-commits": "Branch commits",
28
- "github:file-history": "File history",
29
- "reddit:posts": "Posts",
30
- "reddit:post-comments": "Post comments",
31
- "reddit:comments": "Comments",
32
- "reddit:multireddit": "Multireddit",
33
- "gitlab:activity": "Activity",
34
- "gitlab:releases": "Releases",
35
- "gitlab:tags": "Tags",
36
- "codeberg:activity": "Activity",
37
- "codeberg:releases": "Releases",
38
- "codeberg:tags": "Tags",
39
- "codeberg:branch-commits": "Branch commits",
40
- "codeberg:file-history": "File history",
41
- "wordpress:category": "Category",
42
- "wordpress:tag": "Tag",
43
- "wordpress:author": "Author",
44
- "wordpress:posts-rss2": "Posts (RSS 2.0)",
45
- "wordpress:posts-rss2-alt": "Posts (RSS 2.0)",
46
- "wordpress:posts-rdf": "Posts (RDF)",
47
- "wordpress:posts-atom": "Posts (Atom)",
48
- "wordpress:comments": "Comments",
49
- "wordpress:comments-rss2": "Comments (RSS 2.0)",
50
- "wordpress:comments-rdf": "Comments (RDF)",
51
- "wordpress:comments-atom": "Comments (Atom)",
52
- "blogspot:label": "Label",
53
- "blogspot:posts-atom": "Posts (Atom)",
54
- "blogspot:posts-rss": "Posts (RSS)",
55
- "behance:portfolio": "Portfolio",
56
- "behance:appreciated": "Appreciated",
57
- "bluesky:posts": "Posts",
58
- "dailymotion:videos": "Videos",
59
- "dailymotion:playlist": "Playlist",
60
- "deviantart:tag": "Tag",
61
- "deviantart:favorites": "Favorites",
62
- "deviantart:gallery": "Gallery",
63
- "deviantart:deviations": "Deviations",
64
- "devto:posts": "Posts",
65
- "devto:tag": "Tag",
66
- "github-gist:gists": "Gists",
67
- "github-gist:starred": "Starred",
68
- "kickstarter:updates": "Updates",
69
- "kickstarter:projects": "Projects",
70
- "letterboxd:diary": "Diary",
71
- "lobsters:tag": "Tag",
72
- "lobsters:domain": "Domain",
73
- "lobsters:stories": "Stories",
74
- "lobsters:top": "Top stories",
75
- "lobsters:newest": "Newest",
76
- "lobsters:comments": "Comments",
77
- "mastodon:posts": "Posts",
78
- "mastodon:tag": "Tag",
79
- "medium:posts": "Posts",
80
- "medium:tag": "Tag",
81
- "medium:tagged": "Tagged",
82
- "medium:publication": "Publication",
83
- "pinterest:pins": "Pins",
84
- "producthunt:topic": "Topic",
85
- "producthunt:category": "Category",
86
- "producthunt:products": "Products",
87
- "soundcloud:tracks": "Tracks",
88
- "stackexchange:tag": "Tag",
89
- "stackexchange:question": "Question",
90
- "stackexchange:user": "User",
91
- "steam:news": "News",
92
- "steam:group": "Group",
93
- "substack:newsletter": "Newsletter",
94
- "tumblr:posts": "Posts",
95
- "tumblr:tag": "Tag",
96
- "goodreads:updates": "Updates",
97
- "goodreads:reviews": "Reviews",
98
- "sourceforge:activity": "Activity",
99
- "vimeo:videos": "Videos",
100
- "vimeo:likes": "Likes",
101
- "vimeo:channel": "Channel",
102
- "vimeo:group": "Group",
103
- "hashnode:blog": "Blog",
104
- "paragraph:blog": "Blog",
105
- "hatenablog:posts-rss": "Posts (RSS)",
106
- "hatenablog:posts-atom": "Posts (Atom)",
107
- "hatenablog:category-rss": "Category (RSS)",
108
- "hatenablog:category-atom": "Category (Atom)",
109
- "hatenablog:author-rss": "Author (RSS)",
110
- "hatenablog:author-atom": "Author (Atom)",
111
- "itchio:devlog": "Devlog",
112
- "itchio:games": "Games",
113
- "itchio:tag": "Tag",
114
- "itchio:section": "Section",
115
- "itchio:featured": "Featured",
116
- "itchio:new": "New",
117
- "itchio:sales": "Sales",
118
- "csdn:blog": "Blog",
119
- "douban:interests": "Interests",
120
- "douban:reviews": "Reviews",
121
- "douban:notes": "Notes",
122
- "douban:subjectReviews": "Subject reviews",
123
- "v2ex:index": "Index",
124
- "v2ex:node": "Node",
125
- "v2ex:member": "Member",
126
- "v2ex:tab": "Tab",
127
- "ximalaya:album": "Album",
128
- "lemmy:community": "Community",
129
- "lemmy:user": "User",
130
- "apple-podcasts:podcast": "Podcast"
131
- };
132
- //#endregion
133
- export { errors, hints };
@@ -1,8 +0,0 @@
1
- import { generateUrlCombinations } from "./utils.js";
2
- //#region src/common/uris/guess/index.ts
3
- const discoverUrisFromGuess = (options) => {
4
- const { baseUrl, uris, additionalBaseUrls = [] } = options;
5
- return generateUrlCombinations([baseUrl, ...additionalBaseUrls], uris);
6
- };
7
- //#endregion
8
- export { discoverUrisFromGuess };
@@ -1,40 +0,0 @@
1
- //#region src/common/uris/guess/utils.ts
2
- const ipAddressRegex = /^\d+\.\d+\.\d+\.\d+$/;
3
- const resolveUri = (uri, base, origin, pathname) => {
4
- if (uri.startsWith("/")) return `${origin}${uri}`;
5
- if (uri.startsWith("?")) return `${origin}${pathname}${uri}`;
6
- return new URL(uri, base).href;
7
- };
8
- const generateUrlCombinations = (baseUrls, uris) => {
9
- return baseUrls.flatMap((base) => {
10
- const parsed = new URL(base);
11
- const origin = parsed.origin;
12
- const pathname = parsed.pathname;
13
- return uris.map((uri) => {
14
- if (typeof uri === "string") return resolveUri(uri, base, origin, pathname);
15
- return uri.map((alternative) => resolveUri(alternative, base, origin, pathname));
16
- });
17
- });
18
- };
19
- const getWwwCounterpart = (baseUrl) => {
20
- const url = new URL(baseUrl);
21
- const port = url.port ? `:${url.port}` : "";
22
- if (url.hostname.startsWith("www.")) return `${url.protocol}//${url.hostname.slice(4)}${port}`;
23
- return `${url.protocol}//www.${url.hostname}${port}`;
24
- };
25
- const getSubdomainVariants = (baseUrl, prefixes) => {
26
- const url = new URL(baseUrl);
27
- const hostname = url.hostname;
28
- const isIpAddress = ipAddressRegex.test(hostname);
29
- if (hostname === "localhost" || isIpAddress) return [];
30
- const hostnameParts = hostname.split(".");
31
- if (hostnameParts.length < 2) return [];
32
- const rootDomain = hostnameParts.slice(-2).join(".");
33
- const protocol = url.protocol;
34
- const port = url.port ? `:${url.port}` : "";
35
- return prefixes.map((prefix) => {
36
- return `${protocol}//${prefix === "" ? rootDomain : `${prefix}.${rootDomain}`}${port}`;
37
- });
38
- };
39
- //#endregion
40
- export { generateUrlCombinations, getSubdomainVariants, getWwwCounterpart };
@@ -1,26 +0,0 @@
1
- import { matchesAnyOfLinkSelectors } from "../../utils.js";
2
- //#region src/common/uris/headers/index.ts
3
- const linkSplitRegex = /,(?=\s*<)/;
4
- const urlRegex = /<([^<>]+)>/;
5
- const relRegex = /rel\s*=\s*["']?([^"';,]+)["']?/i;
6
- const typeRegex = /type\s*=\s*["']?([^"';,]+)["']?/i;
7
- const discoverUrisFromHeaders = (headers, options) => {
8
- const uris = /* @__PURE__ */ new Set();
9
- const linkHeader = headers.get("link");
10
- if (!linkHeader) return [];
11
- const links = linkHeader.split(linkSplitRegex);
12
- for (const link of links) {
13
- const urlMatch = link.match(urlRegex);
14
- const relMatch = link.match(relRegex);
15
- const typeMatch = link.match(typeRegex);
16
- if (!urlMatch) continue;
17
- const url = urlMatch[1];
18
- const rel = relMatch?.[1]?.toLowerCase();
19
- const type = typeMatch?.[1];
20
- if (!rel) continue;
21
- if (matchesAnyOfLinkSelectors(rel, type, options.linkSelectors)) uris.add(url);
22
- }
23
- return [...uris];
24
- };
25
- //#endregion
26
- export { discoverUrisFromHeaders };
@@ -1,12 +0,0 @@
1
- import { LinkSelector } from "../../types.js";
2
-
3
- //#region src/common/uris/html/types.d.ts
4
- type HtmlMethodOptions = {
5
- baseUrl?: string;
6
- linkSelectors: Array<LinkSelector>;
7
- anchorUris: Array<string>;
8
- anchorIgnoredUris: Array<string>;
9
- anchorLabels: Array<string>;
10
- };
11
- //#endregion
12
- export { HtmlMethodOptions };
@@ -1,10 +0,0 @@
1
- //#region src/common/utils.d.ts
2
- declare const isSubdomainOf: (url: string, domains: string | Array<string>) => boolean;
3
- declare const isHostOf: (url: string, hosts: string | Array<string>) => boolean;
4
- declare const includesAnyOf: (value: string, patterns: Array<string>, parser?: (value: string) => string) => boolean;
5
- declare const isAnyOf: (value: string, patterns: Array<string>, parser?: (value: string) => string) => boolean;
6
- declare const anyWordMatchesAnyOf: (value: string, patterns: Array<string>) => boolean;
7
- declare const endsWithAnyOf: (value: string, patterns: Array<string>) => boolean;
8
- declare const omitEmpty: <T>(array: Array<T | null | undefined>) => Array<T>;
9
- //#endregion
10
- export { anyWordMatchesAnyOf, endsWithAnyOf, includesAnyOf, isAnyOf, isHostOf, isSubdomainOf, omitEmpty };
@@ -1,79 +0,0 @@
1
- import { hints } from "./locales.js";
2
- //#region src/common/utils.ts
3
- const whitespaceRegex = /\s+/;
4
- const composeHint = (key) => ({
5
- key,
6
- label: hints[key]
7
- });
8
- const normalizeMimeType = (type) => {
9
- return type.split(";")[0].trim().toLowerCase();
10
- };
11
- const isSubdomainOf = (url, domains) => {
12
- try {
13
- const hostname = new URL(url).hostname.toLowerCase();
14
- return (Array.isArray(domains) ? domains : [domains]).some((domain) => hostname.endsWith(`.${domain}`));
15
- } catch {}
16
- return false;
17
- };
18
- const isHostOf = (url, hosts) => {
19
- try {
20
- const list = Array.isArray(hosts) ? hosts : [hosts];
21
- return isAnyOf(new URL(url).hostname, list);
22
- } catch {}
23
- return false;
24
- };
25
- const includesAnyOf = (value, patterns, parser) => {
26
- const parsedValue = parser ? parser(value) : value?.toLowerCase();
27
- return patterns.some((pattern) => pattern && parsedValue?.includes(pattern.toLowerCase()));
28
- };
29
- const isAnyOf = (value, patterns, parser) => {
30
- const parsedValue = parser ? parser(value) : value?.toLowerCase()?.trim();
31
- return patterns.some((pattern) => parsedValue === pattern.toLowerCase().trim());
32
- };
33
- const anyWordMatchesAnyOf = (value, patterns) => {
34
- return value.toLowerCase().split(whitespaceRegex).some((word) => isAnyOf(word, patterns));
35
- };
36
- const endsWithAnyOf = (value, patterns) => {
37
- const lowerValue = value.toLowerCase();
38
- return patterns.some((pattern) => pattern && lowerValue.endsWith(pattern.toLowerCase()));
39
- };
40
- const isOfAllowedMimeType = (type, allowedTypes) => {
41
- if (allowedTypes.length === 0) return true;
42
- if (!type) return false;
43
- return isAnyOf(type, allowedTypes, normalizeMimeType);
44
- };
45
- const hasMetaContent = (content, name, value) => {
46
- const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
47
- const escapedValue = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
48
- return new RegExp(`<meta(?=[^>]*(?:name|property)=["']${escapedName}["'])(?=[^>]*content=["']${escapedValue})`, "i").test(content);
49
- };
50
- const omitEmpty = (array) => {
51
- const result = [];
52
- for (const item of array) if (item != null && item !== "") result.push(item);
53
- return result;
54
- };
55
- const matchesAnyOfLinkSelectors = (rel, type, selectors) => {
56
- return selectors.some((selector) => {
57
- if (!anyWordMatchesAnyOf(rel, [selector.rel])) return false;
58
- if (!selector.types) return true;
59
- return isOfAllowedMimeType(type, selector.types);
60
- });
61
- };
62
- const processConcurrently = async (items, processFn, options) => {
63
- if (options.concurrency < 1) return;
64
- const active = /* @__PURE__ */ new Set();
65
- let index = 0;
66
- while (index < items.length || active.size > 0) {
67
- if (options.shouldStop?.()) break;
68
- while (active.size < options.concurrency && index < items.length) {
69
- const item = items[index++];
70
- const promise = processFn(item).catch(() => {}).finally(() => {
71
- active.delete(promise);
72
- });
73
- active.add(promise);
74
- }
75
- if (active.size > 0) await Promise.race(active);
76
- }
77
- };
78
- //#endregion
79
- export { anyWordMatchesAnyOf, composeHint, endsWithAnyOf, hasMetaContent, includesAnyOf, isAnyOf, isHostOf, isSubdomainOf, matchesAnyOfLinkSelectors, omitEmpty, processConcurrently };
@@ -1,168 +0,0 @@
1
- import { codebergHandler } from "./platform/handlers/codeberg.js";
2
- import { deviantartHandler } from "./platform/handlers/deviantart.js";
3
- import { devtoHandler } from "./platform/handlers/devto.js";
4
- import { githubHandler } from "./platform/handlers/github.js";
5
- import { githubGistHandler } from "./platform/handlers/githubGist.js";
6
- import { gitlabHandler } from "./platform/handlers/gitlab.js";
7
- import { lobstersHandler } from "./platform/handlers/lobsters.js";
8
- import { redditHandler } from "./platform/handlers/reddit.js";
9
- import { sourceforgeHandler } from "./platform/handlers/sourceforge.js";
10
- import { tumblrHandler } from "./platform/handlers/tumblr.js";
11
- import { applePodcastsHandler } from "./platform/handlers/applePodcasts.js";
12
- import { behanceHandler } from "./platform/handlers/behance.js";
13
- import { blogspotHandler } from "./platform/handlers/blogspot.js";
14
- import { blueskyHandler } from "./platform/handlers/bluesky.js";
15
- import { csdnHandler } from "./platform/handlers/csdn.js";
16
- import { dailymotionHandler } from "./platform/handlers/dailymotion.js";
17
- import { doubanHandler } from "./platform/handlers/douban.js";
18
- import { goodreadsHandler } from "./platform/handlers/goodreads.js";
19
- import { hashnodeHandler } from "./platform/handlers/hashnode.js";
20
- import { hatenablogHandler } from "./platform/handlers/hatenablog.js";
21
- import { itchioHandler } from "./platform/handlers/itchio.js";
22
- import { kickstarterHandler } from "./platform/handlers/kickstarter.js";
23
- import { lemmyHandler } from "./platform/handlers/lemmy.js";
24
- import { letterboxdHandler } from "./platform/handlers/letterboxd.js";
25
- import { mastodonHandler } from "./platform/handlers/mastodon.js";
26
- import { mediumHandler } from "./platform/handlers/medium.js";
27
- import { paragraphHandler } from "./platform/handlers/paragraph.js";
28
- import { pinterestHandler } from "./platform/handlers/pinterest.js";
29
- import { producthuntHandler } from "./platform/handlers/producthunt.js";
30
- import { soundcloudHandler } from "./platform/handlers/soundcloud.js";
31
- import { stackExchangeHandler } from "./platform/handlers/stackExchange.js";
32
- import { steamHandler } from "./platform/handlers/steam.js";
33
- import { substackHandler } from "./platform/handlers/substack.js";
34
- import { v2exHandler } from "./platform/handlers/v2ex.js";
35
- import { vimeoHandler } from "./platform/handlers/vimeo.js";
36
- import { wordpressHandler } from "./platform/handlers/wordpress.js";
37
- import { wpengineHandler } from "./platform/handlers/wpengine.js";
38
- import { ximalayaHandler } from "./platform/handlers/ximalaya.js";
39
- import { youtubeHandler } from "./platform/handlers/youtube.js";
40
- //#region src/feeds/defaults.ts
41
- const mimeTypes = [
42
- "application/rss+xml",
43
- "text/rss+xml",
44
- "application/x-rss+xml",
45
- "application/rss",
46
- "application/atom+xml",
47
- "text/atom+xml",
48
- "application/feed+json",
49
- "application/json",
50
- "application/rdf+xml",
51
- "text/rdf+xml",
52
- "application/atom",
53
- "application/xml",
54
- "text/xml"
55
- ];
56
- const urisMinimal = [
57
- "/feed",
58
- "/rss",
59
- "/atom.xml",
60
- "/feed.xml",
61
- "/rss.xml",
62
- "/index.xml"
63
- ];
64
- const urisBalanced = [
65
- ...urisMinimal,
66
- "/feed/",
67
- "/index.atom",
68
- "/index.rss",
69
- "/feed.json"
70
- ];
71
- const urisComprehensive = [
72
- ...urisBalanced,
73
- "/atom",
74
- "/rss/",
75
- "/rss2.xml",
76
- "/feed.rss",
77
- "/feed.atom",
78
- "/feed.rss.xml",
79
- "/feed.atom.xml",
80
- ["/feed/atom/", "?feed=atom"],
81
- ["/feed/rss/", "?feed=rss"],
82
- ["/feed/rss2/", "?feed=rss2"],
83
- ["/feed/rdf", "?feed=rdf"],
84
- ["/feed/rdf/", "?feed=rdf"],
85
- "/index.rss.xml",
86
- "/index.atom.xml",
87
- "?format=rss",
88
- "?format=atom",
89
- "?rss=1",
90
- "?atom=1",
91
- "/.rss",
92
- "/f.json",
93
- "/f.rss",
94
- "/json",
95
- "/.feed",
96
- ["/comments/feed", "?feed=comments-rss2"],
97
- ["/comments/feed/rss2/", "?feed=comments-rss2"],
98
- ["/comments/feed/rdf/", "?feed=comments-rdf"],
99
- ["/comments/feed/atom/", "?feed=comments-atom"],
100
- "/feeds/posts/default",
101
- "/feeds/posts/default?alt=rss",
102
- "/feeds/comments/default"
103
- ];
104
- const ignoredUris = ["wp-json/oembed/", "wp-json/wp/"];
105
- const anchorLabels = [
106
- "rss",
107
- "feed",
108
- "atom",
109
- "subscribe",
110
- "syndicate",
111
- "syndication",
112
- "json feed"
113
- ];
114
- const linkSelectors = [{
115
- rel: "alternate",
116
- types: mimeTypes
117
- }, { rel: "feed" }];
118
- const defaultHtmlOptions = {
119
- linkSelectors,
120
- anchorUris: urisComprehensive.flat(),
121
- anchorIgnoredUris: ignoredUris,
122
- anchorLabels
123
- };
124
- const defaultHeadersOptions = { linkSelectors };
125
- const defaultGuessOptions = { uris: urisBalanced };
126
- const defaultPlatformOptions = { handlers: [
127
- applePodcastsHandler,
128
- behanceHandler,
129
- blogspotHandler,
130
- blueskyHandler,
131
- csdnHandler,
132
- codebergHandler,
133
- doubanHandler,
134
- deviantartHandler,
135
- dailymotionHandler,
136
- devtoHandler,
137
- goodreadsHandler,
138
- githubHandler,
139
- hashnodeHandler,
140
- hatenablogHandler,
141
- githubGistHandler,
142
- gitlabHandler,
143
- itchioHandler,
144
- kickstarterHandler,
145
- lemmyHandler,
146
- letterboxdHandler,
147
- lobstersHandler,
148
- mastodonHandler,
149
- mediumHandler,
150
- paragraphHandler,
151
- pinterestHandler,
152
- producthuntHandler,
153
- redditHandler,
154
- soundcloudHandler,
155
- sourceforgeHandler,
156
- stackExchangeHandler,
157
- steamHandler,
158
- substackHandler,
159
- tumblrHandler,
160
- v2exHandler,
161
- vimeoHandler,
162
- wordpressHandler,
163
- wpengineHandler,
164
- ximalayaHandler,
165
- youtubeHandler
166
- ] };
167
- //#endregion
168
- export { anchorLabels, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, defaultPlatformOptions, ignoredUris, linkSelectors, mimeTypes, urisBalanced, urisComprehensive, urisMinimal };
@@ -1,36 +0,0 @@
1
- import { composeHint } from "../../../common/utils.js";
2
- //#region src/feeds/platform/handlers/blogspot.ts
3
- const blogspotDomainRegex = /^.+\.blogspot\.(?:com|co\.[a-z]{2}|com\.[a-z]{2}|[a-z]{2,3})$/;
4
- const labelRegex = /^\/search\/label\/([^/]+)/;
5
- const blogspotHandler = {
6
- match: (url) => {
7
- try {
8
- const hostname = new URL(url).hostname.toLowerCase();
9
- return blogspotDomainRegex.test(hostname);
10
- } catch {}
11
- return false;
12
- },
13
- resolve: (url) => {
14
- const { origin, pathname } = new URL(url);
15
- const uris = [];
16
- const labelMatch = pathname.match(labelRegex);
17
- if (labelMatch?.[1]) {
18
- const label = labelMatch[1];
19
- uris.push({
20
- uri: `${origin}/feeds/posts/default/-/${label}`,
21
- hint: composeHint("blogspot:label")
22
- });
23
- }
24
- uris.push({
25
- uri: `${origin}/feeds/posts/default`,
26
- hint: composeHint("blogspot:posts-atom")
27
- });
28
- uris.push({
29
- uri: `${origin}/feeds/posts/default?alt=rss`,
30
- hint: composeHint("blogspot:posts-rss")
31
- });
32
- return uris;
33
- }
34
- };
35
- //#endregion
36
- export { blogspotHandler };
@@ -1,46 +0,0 @@
1
- import { composeHint, hasMetaContent } from "../../../common/utils.js";
2
- //#region src/feeds/platform/handlers/lemmy.ts
3
- const lemmyPoweredByRegex = /lemmy/i;
4
- const isCommunityPath = (pathname) => {
5
- const segments = pathname.split("/").filter(Boolean);
6
- return segments.length >= 2 && segments[0] === "c";
7
- };
8
- const isUserPath = (pathname) => {
9
- const segments = pathname.split("/").filter(Boolean);
10
- return segments.length >= 2 && segments[0] === "u";
11
- };
12
- const isLemmyHtml = (content) => {
13
- return hasMetaContent(content, "generator", "Lemmy");
14
- };
15
- const isLemmyHeaders = (headers) => {
16
- const poweredBy = headers.get("x-powered-by") ?? "";
17
- return lemmyPoweredByRegex.test(poweredBy);
18
- };
19
- const lemmyHandler = {
20
- match: (url, content, headers) => {
21
- try {
22
- const { pathname } = new URL(url);
23
- if (!isCommunityPath(pathname) && !isUserPath(pathname)) return false;
24
- if (content && isLemmyHtml(content)) return true;
25
- if (headers && isLemmyHeaders(headers)) return true;
26
- } catch {}
27
- return false;
28
- },
29
- resolve: (url) => {
30
- try {
31
- const { origin, pathname } = new URL(url);
32
- const segments = pathname.split("/").filter(Boolean);
33
- if (isCommunityPath(pathname) && segments[1]) return [{
34
- uri: `${origin}/feeds/c/${segments[1]}.xml`,
35
- hint: composeHint("lemmy:community")
36
- }];
37
- if (isUserPath(pathname) && segments[1]) return [{
38
- uri: `${origin}/feeds/u/${segments[1]}.xml`,
39
- hint: composeHint("lemmy:user")
40
- }];
41
- } catch {}
42
- return [];
43
- }
44
- };
45
- //#endregion
46
- export { lemmyHandler };
@@ -1,74 +0,0 @@
1
- import { composeHint, isAnyOf, isHostOf } from "../../../common/utils.js";
2
- //#region src/feeds/platform/handlers/reddit.ts
3
- const commentsRegex = /^\/r\/([^/]+)\/comments\/([^/]+)/;
4
- const subredditRegex = /^\/r\/([^/]+)(?:\/([^/]+))?/;
5
- const multiredditRegex = /^\/user\/([^/]+)\/m\/([^/]+)/;
6
- const userRegex = /^\/(u|user)\/([^/]+)/;
7
- const domainRegex = /^\/domain\/([^/]+)/;
8
- const hosts = [
9
- "reddit.com",
10
- "www.reddit.com",
11
- "old.reddit.com",
12
- "new.reddit.com"
13
- ];
14
- const sortOptions = [
15
- "hot",
16
- "new",
17
- "rising",
18
- "controversial",
19
- "top"
20
- ];
21
- const redditHandler = {
22
- match: (url) => {
23
- return isHostOf(url, hosts);
24
- },
25
- resolve: (url) => {
26
- const { pathname } = new URL(url);
27
- if (pathname.split("/").filter(Boolean).length === 0) return [{
28
- uri: "https://www.reddit.com/.rss",
29
- hint: composeHint("reddit:posts")
30
- }];
31
- const commentsMatch = pathname.match(commentsRegex);
32
- if (commentsMatch?.[1] && commentsMatch?.[2]) return [{
33
- uri: `https://www.reddit.com/r/${commentsMatch[1]}/comments/${commentsMatch[2]}/.rss`,
34
- hint: composeHint("reddit:post-comments")
35
- }];
36
- const subredditMatch = pathname.match(subredditRegex);
37
- if (subredditMatch?.[1]) {
38
- const subreddit = subredditMatch[1];
39
- const sort = subredditMatch[2];
40
- const uris = [];
41
- if (sort && isAnyOf(sort, sortOptions)) uris.push({
42
- uri: `https://www.reddit.com/r/${subreddit}/${sort}/.rss`,
43
- hint: composeHint("reddit:posts")
44
- });
45
- else uris.push({
46
- uri: `https://www.reddit.com/r/${subreddit}/.rss`,
47
- hint: composeHint("reddit:posts")
48
- });
49
- uris.push({
50
- uri: `https://www.reddit.com/r/${subreddit}/comments/.rss`,
51
- hint: composeHint("reddit:comments")
52
- });
53
- return uris;
54
- }
55
- const multiredditMatch = pathname.match(multiredditRegex);
56
- if (multiredditMatch?.[1] && multiredditMatch?.[2]) return [{
57
- uri: `https://www.reddit.com/user/${multiredditMatch[1]}/m/${multiredditMatch[2]}/.rss`,
58
- hint: composeHint("reddit:multireddit")
59
- }];
60
- const userMatch = pathname.match(userRegex);
61
- if (userMatch?.[2]) return [{
62
- uri: `https://www.reddit.com/user/${userMatch[2]}/.rss`,
63
- hint: composeHint("reddit:posts")
64
- }];
65
- const domainMatch = pathname.match(domainRegex);
66
- if (domainMatch?.[1]) return [{
67
- uri: `https://www.reddit.com/domain/${domainMatch[1]}/.rss`,
68
- hint: composeHint("reddit:posts")
69
- }];
70
- return [];
71
- }
72
- };
73
- //#endregion
74
- export { hosts, redditHandler };
@@ -1,19 +0,0 @@
1
- import { composeHint, isHostOf } from "../../../common/utils.js";
2
- //#region src/feeds/platform/handlers/sourceforge.ts
3
- const hosts = ["sourceforge.net", "www.sourceforge.net"];
4
- const sourceforgeHandler = {
5
- match: (url) => {
6
- return isHostOf(url, hosts);
7
- },
8
- resolve: (url) => {
9
- const { origin, pathname } = new URL(url);
10
- const pathSegments = pathname.split("/").filter(Boolean);
11
- if (pathSegments[0] === "projects" && pathSegments[1]) return [{
12
- uri: `${origin}/projects/${pathSegments[1]}/rss`,
13
- hint: composeHint("sourceforge:activity")
14
- }];
15
- return [];
16
- }
17
- };
18
- //#endregion
19
- export { hosts, sourceforgeHandler };