gs-x-parser 1.0.2 → 1.0.3

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.
package/lib/dom.cjs ADDED
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var frsProbe = require('gs-dom/frs-probe');
3
+ const DomIdReg = /status\/(\d+)/;
4
+ function parseTweetIdByDom(el) {
5
+ const href = el?.querySelector('a[href*="/status/"]')?.href;
6
+ return DomIdReg.exec(href || "")?.[1];
7
+ }
8
+ function parseTweetIdByProps(el) {
9
+ return getTweetIdByProps(frsProbe.getReactProps(el)) || parseTweetIdByDom(el);
10
+ }
11
+ function getTweetIdByProps(props) {
12
+ if (props.entry?.content?.targetTweets?.["0"])
13
+ return props.entry.content.targetTweets[0];
14
+ if (props.children?.entry?.content?.targetTweets?.["0"])
15
+ return props.children.entry.content.targetTweets[0];
16
+ if (props.children?.props?.entry?.content?.targetTweets?.["0"])
17
+ return props.children.props.entry.content.targetTweets[0];
18
+ if (props.children?.props?.children?.props?.entry?.content?.targetTweets?.["0"])
19
+ return props.children.props.children.props.entry.content.targetTweets[0];
20
+ if (props.entry?.content?.url?.url) {
21
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.entry.content.url.url);
22
+ if (tweetIdFromUrl)
23
+ return tweetIdFromUrl;
24
+ } else if (props.children?.entry?.content?.url?.url) {
25
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.children.entry.content.url.url);
26
+ if (tweetIdFromUrl)
27
+ return tweetIdFromUrl;
28
+ } else if (props.children?.props?.entry?.content?.url?.url) {
29
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.children.props.entry.content.url.url);
30
+ if (tweetIdFromUrl)
31
+ return tweetIdFromUrl;
32
+ } else if (props.children?.props?.children?.props?.entry?.content?.url?.url) {
33
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.children.props.children.props.entry.content.url.url);
34
+ if (tweetIdFromUrl)
35
+ return tweetIdFromUrl;
36
+ }
37
+ if (props.children?.["2"]?.props?.tweet?.id_str)
38
+ return props.children?.[2].props.tweet.id_str;
39
+ if (props.children?.props?.tweet?.id_str)
40
+ return props.children.props.tweet.id_str;
41
+ if (props.children?.props?.children?.props?.tweet?.id_str)
42
+ return props.children.props.children.props.tweet.id_str;
43
+ let displayType;
44
+ if (props.displayType ? displayType = props.displayType : props.children?.displayType ? displayType = props.children.displayType : props.children?.props?.displayType ? displayType = props.children.props.displayType : props.children?.props?.children?.props?.displayType ? displayType = props.children.props.children.props.displayType : props.entry?.content?.displayType ? displayType = props.entry.content.displayType : props.children?.entry?.content?.displayType ? displayType = props.children.entry.content.displayType : props.children?.props?.entry?.content?.displayType ? displayType = props.children.props.entry.content.displayType : props.children?.props?.children?.props?.entry?.content?.displayType && (displayType = props.children.props.children.props.entry.content.displayType), displayType !== "Tweet" && displayType !== "FocalTweet" && displayType !== "MediaGrid")
45
+ return props.children?.sibling ? getTweetIdFromSibling(props.children.sibling) : props.children?._owner?.sibling ? getTweetIdFromSibling(props.children._owner.sibling) : props.children?.props?.sibling ? getTweetIdFromSibling(props.children.props.sibling) : props.children?._owner?.return?.sibling ? getTweetIdFromSibling(props.children._owner.return.sibling) : void 0;
46
+ let contentId;
47
+ if (props.entry?.content?.id ? contentId = props.entry.content.id : props.children?.entry?.content?.id ? contentId = props.children.entry.content.id : props.children?.props?.entry?.content?.id ? contentId = props.children.props.entry.content.id : props.children?.props?.children?.props?.entry?.content?.id ? contentId = props.children.props.children.props.entry.content.id : props.item?.id ? contentId = props.item.id : props.children?.item?.id ? contentId = props.children.item.id : props.children?.props?.item?.id ? contentId = props.children.props.item.id : props.item?.data?.content?.id ? contentId = props.item.data.content.id : props.children?.item?.data?.content?.id ? contentId = props.children.item.data.content.id : props.children?.props?.item?.data?.content?.id && (contentId = props.children.props.item.data.content.id), contentId)
48
+ return contentId;
49
+ let entryId;
50
+ if (props.entry?.entryId ? entryId = props.entry.entryId : props.children?.entry?.entryId ? entryId = props.children.entry.entryId : props.children?.props?.entry?.entryId ? entryId = props.children.props.entry.entryId : props.children?.props?.children?.props?.entry?.entryId ? entryId = props.children.props.children.props.entry.entryId : props.item?.data?.entryId ? entryId = props.item.data.entryId : props.children?.item?.data?.entryId ? entryId = props.children.item.data.entryId : props.children?.props?.item?.data?.entryId && (entryId = props.children.props.item.data.entryId), entryId && entryId.startsWith("tweet-"))
51
+ return entryId.substring(6);
52
+ }
53
+ function extractTweetIdFromUrl(url) {
54
+ const match = url.match(/\/status\/(\d+)/);
55
+ if (match && match[1])
56
+ return match[1];
57
+ }
58
+ function getTweetIdFromSibling(sibling) {
59
+ if (sibling.key && sibling.key.startsWith("tweet-"))
60
+ return sibling.key.substring(6);
61
+ if (sibling.props?.item?.id && sibling.props.item.id.startsWith("tweet-"))
62
+ return sibling.props.item.id.substring(6);
63
+ if (sibling.props?.item?.data?.content?.id)
64
+ return sibling.props.item.data.content.id;
65
+ if (sibling.props?.item?.data?.entryId && sibling.props.item.data.entryId.startsWith("tweet-"))
66
+ return sibling.props.item.data.entryId.substring(6);
67
+ if (sibling.sibling)
68
+ return getTweetIdFromSibling(sibling.sibling);
69
+ }
70
+ function parseUserIdByProps(el) {
71
+ return getTweetUserIdByProps(frsProbe.getReactProps(el)) || parseTweetIdByDom(el);
72
+ }
73
+ function getTweetUserIdByProps(props) {
74
+ if (!props)
75
+ return;
76
+ if (props.entry?.content?.fromUsers?.["0"])
77
+ return props.entry.content.fromUsers[0];
78
+ if (props.children?.entry?.content?.fromUsers?.["0"])
79
+ return props.children.entry.content.fromUsers[0];
80
+ if (props.children?.props?.entry?.content?.fromUsers?.["0"])
81
+ return props.children.props.entry.content.fromUsers[0];
82
+ if (props.children?.props?.children?.props?.entry?.content?.fromUsers?.["0"])
83
+ return props.children.props.children.props.entry.content.fromUsers[0];
84
+ let displayType;
85
+ if (props.displayType ? displayType = props.displayType : props.children?.displayType ? displayType = props.children.displayType : props.children?.props?.displayType ? displayType = props.children.props.displayType : props.children?.props?.children?.props?.displayType ? displayType = props.children.props.children.props.displayType : props.entry?.content?.displayType ? displayType = props.entry.content.displayType : props.children?.entry?.content?.displayType ? displayType = props.children.entry.content.displayType : props.children?.props?.entry?.content?.displayType ? displayType = props.children.props.entry.content.displayType : props.children?.props?.children?.props?.entry?.content?.displayType && (displayType = props.children.props.children.props.entry.content.displayType), displayType === "User") {
86
+ if (props.entry?.content?.id)
87
+ return props.entry.content.id;
88
+ if (props.children?.entry?.content?.id)
89
+ return props.children.entry.content.id;
90
+ if (props.children?.props?.entry?.content?.id)
91
+ return props.children.props.entry.content.id;
92
+ if (props.children?.props?.children?.props?.entry?.content?.id)
93
+ return props.children.props.children.props.entry.content.id;
94
+ if (props.item?.id)
95
+ return props.item.id;
96
+ if (props.children?.item?.id)
97
+ return props.children.item.id;
98
+ if (props.children?.props?.item?.id)
99
+ return props.children.props.item.id;
100
+ if (props.item?.data?.content?.id)
101
+ return props.item.data.content.id;
102
+ if (props.children?.item?.data?.content?.id)
103
+ return props.children.item.data.content.id;
104
+ if (props.children?.props?.item?.data?.content?.id)
105
+ return props.children.props.item.data.content.id;
106
+ }
107
+ }
108
+ const cellSelector = '[data-testid="cellInnerDiv"]', cellInnerSelector = `${cellSelector} [aria-labelledby^="id__"]`, cellPreviewSelector = `${cellSelector} [data-testid="previewInterstitial"]`, itemSelector = `${cellSelector} [role="listitem"]`, previewVideoSelector = `${cellPreviewSelector}:not([aria-label*=GIF])`, primaryRegionSelector = 'main [data-testid="primaryColumn"] [role="region"]', primaryCellSelector = `${primaryRegionSelector} ${cellSelector}`, primaryCellInnerSelector = `${primaryRegionSelector} ${cellInnerSelector}`, primaryItemSelector = `${primaryRegionSelector} ${itemSelector}`, primaryTweetSelector = [primaryCellSelector, primaryItemSelector].join(","), primaryPreviewVideoSelector = `${primaryRegionSelector} ${previewVideoSelector}`, ImageVideoIdRegex = /(?:video_thumb|card_img)\/(\d+)/, LinkVideoIdRegex = /status\/(\d+)\/video\/(\d+)/;
109
+ function parseTweetVideoId(el) {
110
+ if (!el) return;
111
+ const itemEl = el.matches(primaryItemSelector) ? el : el.closest(primaryItemSelector);
112
+ return itemEl ? parseTweetVideoIdByVideoContainer(itemEl) : parseTweetVideoIdByVideoContainer(el.matches(primaryPreviewVideoSelector) ? el : el.closest(primaryPreviewVideoSelector), !0);
113
+ }
114
+ function parseTweetVideoIdByVideoContainer(el, defaultTweet) {
115
+ if (!el)
116
+ return;
117
+ const img = el.querySelector('img[src*="video_thumb/"],img[src*="card_img/"]');
118
+ if (img) {
119
+ const videoId = ImageVideoIdRegex.exec(img.src)?.[1];
120
+ if (videoId)
121
+ return { videoId };
122
+ }
123
+ const link = el.querySelector('a[href*="/status/"][href*="/video/"]');
124
+ if (!link) {
125
+ if (!defaultTweet)
126
+ return;
127
+ const tweetId2 = parseTweetIdByDom(el);
128
+ if (tweetId2) {
129
+ let index = Array.from(el.querySelectorAll(primaryPreviewVideoSelector)).indexOf(el);
130
+ return index === -1 && (index = 0), { index, tweetId: tweetId2 };
131
+ }
132
+ return;
133
+ }
134
+ const match = LinkVideoIdRegex.exec(link.href), tweetId = match?.[1];
135
+ if (!tweetId)
136
+ return {
137
+ tweetId,
138
+ index: parseInt(match[2]) || 0
139
+ };
140
+ }
141
+ exports.cellInnerSelector = cellInnerSelector, exports.cellPreviewSelector = cellPreviewSelector, exports.cellSelector = cellSelector, exports.getTweetIdByProps = getTweetIdByProps, exports.itemSelector = itemSelector, exports.parseTweetIdByDom = parseTweetIdByDom, exports.parseTweetIdByProps = parseTweetIdByProps, exports.parseTweetVideoId = parseTweetVideoId, exports.parseTweetVideoIdByVideoContainer = parseTweetVideoIdByVideoContainer, exports.parseUserIdByProps = parseUserIdByProps, exports.previewVideoSelector = previewVideoSelector, exports.primaryCellInnerSelector = primaryCellInnerSelector, exports.primaryCellSelector = primaryCellSelector, exports.primaryItemSelector = primaryItemSelector, exports.primaryPreviewVideoSelector = primaryPreviewVideoSelector, exports.primaryRegionSelector = primaryRegionSelector, exports.primaryTweetSelector = primaryTweetSelector;
package/lib/dom.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { IReactXCellDivProps, IGetTweetVideoIdResult } from './type.d.ts';
2
+
3
+ declare function parseTweetIdByProps(el: Element): string | undefined;
4
+ /**
5
+ * 获取 Tweet 或 FocalTweet 类型的内容 ID
6
+ * @param props React 组件属性
7
+ * @returns 内容 ID,如果不存在则返回 undefined
8
+ */
9
+ declare function getTweetIdByProps(props: IReactXCellDivProps): string | undefined;
10
+
11
+ declare function parseUserIdByProps(el: Element): string | undefined;
12
+
13
+ declare function parseTweetIdByDom(el: Element): string | undefined;
14
+
15
+ declare function parseTweetVideoId(el: Element): IGetTweetVideoIdResult | undefined;
16
+ declare function parseTweetVideoIdByVideoContainer(el: HTMLElement, defaultTweet?: boolean): IGetTweetVideoIdResult | undefined;
17
+
18
+ declare const cellSelector = "[data-testid=\"cellInnerDiv\"]";
19
+ declare const cellInnerSelector = "[data-testid=\"cellInnerDiv\"] [aria-labelledby^=\"id__\"]";
20
+ declare const cellPreviewSelector = "[data-testid=\"cellInnerDiv\"] [data-testid=\"previewInterstitial\"]";
21
+ declare const itemSelector = "[data-testid=\"cellInnerDiv\"] [role=\"listitem\"]";
22
+ declare const previewVideoSelector = "[data-testid=\"cellInnerDiv\"] [data-testid=\"previewInterstitial\"]:not([aria-label*=GIF])";
23
+ declare const primaryRegionSelector = "main [data-testid=\"primaryColumn\"] [role=\"region\"]";
24
+ declare const primaryCellSelector = "main [data-testid=\"primaryColumn\"] [role=\"region\"] [data-testid=\"cellInnerDiv\"]";
25
+ declare const primaryCellInnerSelector = "main [data-testid=\"primaryColumn\"] [role=\"region\"] [data-testid=\"cellInnerDiv\"] [aria-labelledby^=\"id__\"]";
26
+ declare const primaryItemSelector = "main [data-testid=\"primaryColumn\"] [role=\"region\"] [data-testid=\"cellInnerDiv\"] [role=\"listitem\"]";
27
+ declare const primaryTweetSelector: string;
28
+ declare const primaryPreviewVideoSelector = "main [data-testid=\"primaryColumn\"] [role=\"region\"] [data-testid=\"cellInnerDiv\"] [data-testid=\"previewInterstitial\"]:not([aria-label*=GIF])";
29
+
30
+ export { cellInnerSelector, cellPreviewSelector, cellSelector, getTweetIdByProps, itemSelector, parseTweetIdByDom, parseTweetIdByProps, parseTweetVideoId, parseTweetVideoIdByVideoContainer, parseUserIdByProps, previewVideoSelector, primaryCellInnerSelector, primaryCellSelector, primaryItemSelector, primaryPreviewVideoSelector, primaryRegionSelector, primaryTweetSelector };
package/lib/dom.mjs ADDED
@@ -0,0 +1,158 @@
1
+ import { getReactProps } from 'gs-dom/frs-probe';
2
+ const DomIdReg = /status\/(\d+)/;
3
+ function parseTweetIdByDom(el) {
4
+ const href = el?.querySelector('a[href*="/status/"]')?.href;
5
+ return DomIdReg.exec(href || "")?.[1];
6
+ }
7
+ function parseTweetIdByProps(el) {
8
+ return getTweetIdByProps(getReactProps(el)) || parseTweetIdByDom(el);
9
+ }
10
+ function getTweetIdByProps(props) {
11
+ if (props.entry?.content?.targetTweets?.["0"])
12
+ return props.entry.content.targetTweets[0];
13
+ if (props.children?.entry?.content?.targetTweets?.["0"])
14
+ return props.children.entry.content.targetTweets[0];
15
+ if (props.children?.props?.entry?.content?.targetTweets?.["0"])
16
+ return props.children.props.entry.content.targetTweets[0];
17
+ if (props.children?.props?.children?.props?.entry?.content?.targetTweets?.["0"])
18
+ return props.children.props.children.props.entry.content.targetTweets[0];
19
+ if (props.entry?.content?.url?.url) {
20
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.entry.content.url.url);
21
+ if (tweetIdFromUrl)
22
+ return tweetIdFromUrl;
23
+ } else if (props.children?.entry?.content?.url?.url) {
24
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.children.entry.content.url.url);
25
+ if (tweetIdFromUrl)
26
+ return tweetIdFromUrl;
27
+ } else if (props.children?.props?.entry?.content?.url?.url) {
28
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.children.props.entry.content.url.url);
29
+ if (tweetIdFromUrl)
30
+ return tweetIdFromUrl;
31
+ } else if (props.children?.props?.children?.props?.entry?.content?.url?.url) {
32
+ const tweetIdFromUrl = extractTweetIdFromUrl(props.children.props.children.props.entry.content.url.url);
33
+ if (tweetIdFromUrl)
34
+ return tweetIdFromUrl;
35
+ }
36
+ if (props.children?.["2"]?.props?.tweet?.id_str)
37
+ return props.children?.[2].props.tweet.id_str;
38
+ if (props.children?.props?.tweet?.id_str)
39
+ return props.children.props.tweet.id_str;
40
+ if (props.children?.props?.children?.props?.tweet?.id_str)
41
+ return props.children.props.children.props.tweet.id_str;
42
+ let displayType;
43
+ if (props.displayType ? displayType = props.displayType : props.children?.displayType ? displayType = props.children.displayType : props.children?.props?.displayType ? displayType = props.children.props.displayType : props.children?.props?.children?.props?.displayType ? displayType = props.children.props.children.props.displayType : props.entry?.content?.displayType ? displayType = props.entry.content.displayType : props.children?.entry?.content?.displayType ? displayType = props.children.entry.content.displayType : props.children?.props?.entry?.content?.displayType ? displayType = props.children.props.entry.content.displayType : props.children?.props?.children?.props?.entry?.content?.displayType && (displayType = props.children.props.children.props.entry.content.displayType), displayType !== "Tweet" && displayType !== "FocalTweet" && displayType !== "MediaGrid")
44
+ return props.children?.sibling ? getTweetIdFromSibling(props.children.sibling) : props.children?._owner?.sibling ? getTweetIdFromSibling(props.children._owner.sibling) : props.children?.props?.sibling ? getTweetIdFromSibling(props.children.props.sibling) : props.children?._owner?.return?.sibling ? getTweetIdFromSibling(props.children._owner.return.sibling) : void 0;
45
+ let contentId;
46
+ if (props.entry?.content?.id ? contentId = props.entry.content.id : props.children?.entry?.content?.id ? contentId = props.children.entry.content.id : props.children?.props?.entry?.content?.id ? contentId = props.children.props.entry.content.id : props.children?.props?.children?.props?.entry?.content?.id ? contentId = props.children.props.children.props.entry.content.id : props.item?.id ? contentId = props.item.id : props.children?.item?.id ? contentId = props.children.item.id : props.children?.props?.item?.id ? contentId = props.children.props.item.id : props.item?.data?.content?.id ? contentId = props.item.data.content.id : props.children?.item?.data?.content?.id ? contentId = props.children.item.data.content.id : props.children?.props?.item?.data?.content?.id && (contentId = props.children.props.item.data.content.id), contentId)
47
+ return contentId;
48
+ let entryId;
49
+ if (props.entry?.entryId ? entryId = props.entry.entryId : props.children?.entry?.entryId ? entryId = props.children.entry.entryId : props.children?.props?.entry?.entryId ? entryId = props.children.props.entry.entryId : props.children?.props?.children?.props?.entry?.entryId ? entryId = props.children.props.children.props.entry.entryId : props.item?.data?.entryId ? entryId = props.item.data.entryId : props.children?.item?.data?.entryId ? entryId = props.children.item.data.entryId : props.children?.props?.item?.data?.entryId && (entryId = props.children.props.item.data.entryId), entryId && entryId.startsWith("tweet-"))
50
+ return entryId.substring(6);
51
+ }
52
+ function extractTweetIdFromUrl(url) {
53
+ const match = url.match(/\/status\/(\d+)/);
54
+ if (match && match[1])
55
+ return match[1];
56
+ }
57
+ function getTweetIdFromSibling(sibling) {
58
+ if (sibling.key && sibling.key.startsWith("tweet-"))
59
+ return sibling.key.substring(6);
60
+ if (sibling.props?.item?.id && sibling.props.item.id.startsWith("tweet-"))
61
+ return sibling.props.item.id.substring(6);
62
+ if (sibling.props?.item?.data?.content?.id)
63
+ return sibling.props.item.data.content.id;
64
+ if (sibling.props?.item?.data?.entryId && sibling.props.item.data.entryId.startsWith("tweet-"))
65
+ return sibling.props.item.data.entryId.substring(6);
66
+ if (sibling.sibling)
67
+ return getTweetIdFromSibling(sibling.sibling);
68
+ }
69
+ function parseUserIdByProps(el) {
70
+ return getTweetUserIdByProps(getReactProps(el)) || parseTweetIdByDom(el);
71
+ }
72
+ function getTweetUserIdByProps(props) {
73
+ if (!props)
74
+ return;
75
+ if (props.entry?.content?.fromUsers?.["0"])
76
+ return props.entry.content.fromUsers[0];
77
+ if (props.children?.entry?.content?.fromUsers?.["0"])
78
+ return props.children.entry.content.fromUsers[0];
79
+ if (props.children?.props?.entry?.content?.fromUsers?.["0"])
80
+ return props.children.props.entry.content.fromUsers[0];
81
+ if (props.children?.props?.children?.props?.entry?.content?.fromUsers?.["0"])
82
+ return props.children.props.children.props.entry.content.fromUsers[0];
83
+ let displayType;
84
+ if (props.displayType ? displayType = props.displayType : props.children?.displayType ? displayType = props.children.displayType : props.children?.props?.displayType ? displayType = props.children.props.displayType : props.children?.props?.children?.props?.displayType ? displayType = props.children.props.children.props.displayType : props.entry?.content?.displayType ? displayType = props.entry.content.displayType : props.children?.entry?.content?.displayType ? displayType = props.children.entry.content.displayType : props.children?.props?.entry?.content?.displayType ? displayType = props.children.props.entry.content.displayType : props.children?.props?.children?.props?.entry?.content?.displayType && (displayType = props.children.props.children.props.entry.content.displayType), displayType === "User") {
85
+ if (props.entry?.content?.id)
86
+ return props.entry.content.id;
87
+ if (props.children?.entry?.content?.id)
88
+ return props.children.entry.content.id;
89
+ if (props.children?.props?.entry?.content?.id)
90
+ return props.children.props.entry.content.id;
91
+ if (props.children?.props?.children?.props?.entry?.content?.id)
92
+ return props.children.props.children.props.entry.content.id;
93
+ if (props.item?.id)
94
+ return props.item.id;
95
+ if (props.children?.item?.id)
96
+ return props.children.item.id;
97
+ if (props.children?.props?.item?.id)
98
+ return props.children.props.item.id;
99
+ if (props.item?.data?.content?.id)
100
+ return props.item.data.content.id;
101
+ if (props.children?.item?.data?.content?.id)
102
+ return props.children.item.data.content.id;
103
+ if (props.children?.props?.item?.data?.content?.id)
104
+ return props.children.props.item.data.content.id;
105
+ }
106
+ }
107
+ const cellSelector = '[data-testid="cellInnerDiv"]', cellInnerSelector = `${cellSelector} [aria-labelledby^="id__"]`, cellPreviewSelector = `${cellSelector} [data-testid="previewInterstitial"]`, itemSelector = `${cellSelector} [role="listitem"]`, previewVideoSelector = `${cellPreviewSelector}:not([aria-label*=GIF])`, primaryRegionSelector = 'main [data-testid="primaryColumn"] [role="region"]', primaryCellSelector = `${primaryRegionSelector} ${cellSelector}`, primaryCellInnerSelector = `${primaryRegionSelector} ${cellInnerSelector}`, primaryItemSelector = `${primaryRegionSelector} ${itemSelector}`, primaryTweetSelector = [primaryCellSelector, primaryItemSelector].join(","), primaryPreviewVideoSelector = `${primaryRegionSelector} ${previewVideoSelector}`, ImageVideoIdRegex = /(?:video_thumb|card_img)\/(\d+)/, LinkVideoIdRegex = /status\/(\d+)\/video\/(\d+)/;
108
+ function parseTweetVideoId(el) {
109
+ if (!el) return;
110
+ const itemEl = el.matches(primaryItemSelector) ? el : el.closest(primaryItemSelector);
111
+ return itemEl ? parseTweetVideoIdByVideoContainer(itemEl) : parseTweetVideoIdByVideoContainer(el.matches(primaryPreviewVideoSelector) ? el : el.closest(primaryPreviewVideoSelector), !0);
112
+ }
113
+ function parseTweetVideoIdByVideoContainer(el, defaultTweet) {
114
+ if (!el)
115
+ return;
116
+ const img = el.querySelector('img[src*="video_thumb/"],img[src*="card_img/"]');
117
+ if (img) {
118
+ const videoId = ImageVideoIdRegex.exec(img.src)?.[1];
119
+ if (videoId)
120
+ return { videoId };
121
+ }
122
+ const link = el.querySelector('a[href*="/status/"][href*="/video/"]');
123
+ if (!link) {
124
+ if (!defaultTweet)
125
+ return;
126
+ const tweetId2 = parseTweetIdByDom(el);
127
+ if (tweetId2) {
128
+ let index = Array.from(el.querySelectorAll(primaryPreviewVideoSelector)).indexOf(el);
129
+ return index === -1 && (index = 0), { index, tweetId: tweetId2 };
130
+ }
131
+ return;
132
+ }
133
+ const match = LinkVideoIdRegex.exec(link.href), tweetId = match?.[1];
134
+ if (!tweetId)
135
+ return {
136
+ tweetId,
137
+ index: parseInt(match[2]) || 0
138
+ };
139
+ }
140
+ export {
141
+ cellInnerSelector,
142
+ cellPreviewSelector,
143
+ cellSelector,
144
+ getTweetIdByProps,
145
+ itemSelector,
146
+ parseTweetIdByDom,
147
+ parseTweetIdByProps,
148
+ parseTweetVideoId,
149
+ parseTweetVideoIdByVideoContainer,
150
+ parseUserIdByProps,
151
+ previewVideoSelector,
152
+ primaryCellInnerSelector,
153
+ primaryCellSelector,
154
+ primaryItemSelector,
155
+ primaryPreviewVideoSelector,
156
+ primaryRegionSelector,
157
+ primaryTweetSelector
158
+ };
package/lib/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- var type = require('./type.cjs'), parser = require('./parser.cjs');
2
+ var type = require('./type.cjs'), parser = require('./parser.cjs'), listenTweetRegister = require('./listen-tweet-register.cjs'), listenTweetStarter = require('./listen-tweet-starter.cjs'), dom = require('./dom.cjs');
3
3
  Object.keys(type).forEach(function(k) {
4
4
  k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k) && Object.defineProperty(exports, k, {
5
5
  enumerable: !0,
@@ -14,4 +14,25 @@ Object.keys(type).forEach(function(k) {
14
14
  return parser[k];
15
15
  }
16
16
  });
17
+ }), Object.keys(listenTweetRegister).forEach(function(k) {
18
+ k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k) && Object.defineProperty(exports, k, {
19
+ enumerable: !0,
20
+ get: function() {
21
+ return listenTweetRegister[k];
22
+ }
23
+ });
24
+ }), Object.keys(listenTweetStarter).forEach(function(k) {
25
+ k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k) && Object.defineProperty(exports, k, {
26
+ enumerable: !0,
27
+ get: function() {
28
+ return listenTweetStarter[k];
29
+ }
30
+ });
31
+ }), Object.keys(dom).forEach(function(k) {
32
+ k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k) && Object.defineProperty(exports, k, {
33
+ enumerable: !0,
34
+ get: function() {
35
+ return dom[k];
36
+ }
37
+ });
17
38
  });
package/lib/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  export * from './type.d.ts';
2
2
  export * from './parser.d.ts';
3
+ export * from './listen-tweet-register.d.ts';
4
+ export * from './listen-tweet-starter.d.ts';
5
+ export * from './dom.d.ts';
package/lib/index.mjs CHANGED
@@ -1,2 +1,5 @@
1
1
  export * from './type.mjs';
2
2
  export * from './parser.mjs';
3
+ export * from './listen-tweet-register.mjs';
4
+ export * from './listen-tweet-starter.mjs';
5
+ export * from './dom.mjs';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var type = require('./type.cjs'), gsDom = require('gs-dom');
3
+ class ListenRegister {
4
+ static addVideoDetectedListener(listener) {
5
+ gsDom.on(type.ListenTweetEvents.VideoDetected, ({ detail }) => listener(detail));
6
+ }
7
+ static addTweetDetectedListener(listener) {
8
+ gsDom.on(type.ListenTweetEvents.TweetDetected, ({ detail }) => listener(detail));
9
+ }
10
+ static addUserDetectedListener(listener) {
11
+ gsDom.on(type.ListenTweetEvents.UserDetected, ({ detail }) => listener(detail));
12
+ }
13
+ static addTweetRenderedListener(listener) {
14
+ gsDom.on(type.ListenTweetEvents.TweetRendered, ({ detail }) => listener(detail));
15
+ }
16
+ // static addVideoRenderedListener(listener: (tweetIds: IGetTweetVideoIdResult[]) => void) {
17
+ // on(ListenTweetEvents.VideoRendered, ({detail}: CustomEvent) => listener(detail))
18
+ // }
19
+ }
20
+ exports.ListenRegister = ListenRegister;
@@ -0,0 +1,10 @@
1
+ import { ISimpleTweet, ISimpleUser } from './type.d.ts';
2
+
3
+ declare class ListenRegister {
4
+ static addVideoDetectedListener(listener: (videos: ISimpleTweet[]) => void): void;
5
+ static addTweetDetectedListener(listener: (tweets: ISimpleTweet[]) => void): void;
6
+ static addUserDetectedListener(listener: (users: ISimpleUser[]) => void): void;
7
+ static addTweetRenderedListener(listener: (tweetIds: string[]) => void): void;
8
+ }
9
+
10
+ export { ListenRegister };
@@ -0,0 +1,22 @@
1
+ import { ListenTweetEvents } from './type.mjs';
2
+ import { on } from 'gs-dom';
3
+ class ListenRegister {
4
+ static addVideoDetectedListener(listener) {
5
+ on(ListenTweetEvents.VideoDetected, ({ detail }) => listener(detail));
6
+ }
7
+ static addTweetDetectedListener(listener) {
8
+ on(ListenTweetEvents.TweetDetected, ({ detail }) => listener(detail));
9
+ }
10
+ static addUserDetectedListener(listener) {
11
+ on(ListenTweetEvents.UserDetected, ({ detail }) => listener(detail));
12
+ }
13
+ static addTweetRenderedListener(listener) {
14
+ on(ListenTweetEvents.TweetRendered, ({ detail }) => listener(detail));
15
+ }
16
+ // static addVideoRenderedListener(listener: (tweetIds: IGetTweetVideoIdResult[]) => void) {
17
+ // on(ListenTweetEvents.VideoRendered, ({detail}: CustomEvent) => listener(detail))
18
+ // }
19
+ }
20
+ export {
21
+ ListenRegister
22
+ };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var xhr = require('gs-web-hooks/xhr'), parser = require('./parser.cjs'), event = require('gs-dom/event'), type = require('./type.cjs'), frsProbe = require('gs-dom/frs-probe'), observer = require('gs-dom/observer');
3
+ const ListenFlagKey = "__listen-tweet-flag-key";
4
+ class ListenFlag {
5
+ static #flag;
6
+ static get flag() {
7
+ return this.#flag || (this.#flag = self[ListenFlagKey]);
8
+ }
9
+ static isInit(arg) {
10
+ const init = !!this.flag;
11
+ return arg && this.update(arg), init;
12
+ }
13
+ static update(arg) {
14
+ self[ListenFlagKey] ? (arg?.enableTweetDetected && (self[ListenFlagKey].enableTweetDetected = !0), arg?.enableUserDetected && (self[ListenFlagKey].enableUserDetected = !0)) : Object.defineProperty(self, ListenFlagKey, {
15
+ value: { ...arg },
16
+ enumerable: !1,
17
+ configurable: !1,
18
+ writable: !1
19
+ }), this.#flag = self[ListenFlagKey];
20
+ }
21
+ }
22
+ const timelineRegex = /TweetDetail|Timeline|Bookmarks|UserTweets|UserMedia|Likes/, id = "__listen-tweet-interceptor";
23
+ function listenNet() {
24
+ xhr.addXhrInterceptor({
25
+ id,
26
+ before: (url) => timelineRegex.test(url) ? url : void 0,
27
+ after: (text) => {
28
+ const json = JSON.parse(text), { tweets, users, videos } = parser.XParser.parseSimple(json);
29
+ if (videos?.length) try {
30
+ event.trigger(type.ListenTweetEvents.VideoDetected, { detail: videos });
31
+ } catch {
32
+ }
33
+ const flag = ListenFlag.flag || {};
34
+ if (flag.enableTweetDetected && tweets?.length) try {
35
+ event.trigger(type.ListenTweetEvents.UserDetected, { detail: tweets });
36
+ } catch {
37
+ }
38
+ if (flag.enableUserDetected && users?.length) try {
39
+ event.trigger(type.ListenTweetEvents.UserDetected, { detail: users });
40
+ } catch {
41
+ }
42
+ }
43
+ });
44
+ }
45
+ const containerSelector = "main,main *", regionSelector = 'main [data-testid="primaryColumn"] [role="region"]', cellSelector = `${regionSelector} [data-testid="cellInnerDiv"]`, itemSelector = `${cellSelector} [role="listitem"]`, tweetSelector = [cellSelector, itemSelector].join(",");
46
+ function addedElements(els) {
47
+ const tweets = [];
48
+ function processTarget(el) {
49
+ if (el.matches(tweetSelector)) {
50
+ const id2 = frsProbe.getTweetId(el);
51
+ id2 && tweets.push(id2);
52
+ } else el.matches(containerSelector) && el.clientHeight > 300 && els.push(...el.querySelectorAll(tweetSelector));
53
+ }
54
+ for (let i = 0; i < els.length; i++)
55
+ try {
56
+ processTarget(els[i]);
57
+ } catch (e) {
58
+ console.warn(e);
59
+ }
60
+ tweets.length && event.trigger(type.ListenTweetEvents.TweetRendered, { detail: tweets });
61
+ }
62
+ function observePage() {
63
+ observer.observe({ subtree: !0, addedElements });
64
+ }
65
+ function startListen(option) {
66
+ ListenFlag.isInit(option) || (listenNet(), observePage());
67
+ }
68
+ exports.startListen = startListen;
@@ -0,0 +1,9 @@
1
+ interface IListenTweetOption {
2
+ enableTweetDetected?: boolean;
3
+ enableUserDetected?: boolean;
4
+ }
5
+
6
+ declare function startListen(option?: IListenTweetOption): void;
7
+
8
+ export { startListen };
9
+ export type { IListenTweetOption };
@@ -0,0 +1,74 @@
1
+ import { addXhrInterceptor } from 'gs-web-hooks/xhr';
2
+ import { XParser } from './parser.mjs';
3
+ import { trigger } from 'gs-dom/event';
4
+ import { ListenTweetEvents } from './type.mjs';
5
+ import { getTweetId } from 'gs-dom/frs-probe';
6
+ import { observe } from 'gs-dom/observer';
7
+ const ListenFlagKey = "__listen-tweet-flag-key";
8
+ class ListenFlag {
9
+ static #flag;
10
+ static get flag() {
11
+ return this.#flag || (this.#flag = self[ListenFlagKey]);
12
+ }
13
+ static isInit(arg) {
14
+ const init = !!this.flag;
15
+ return arg && this.update(arg), init;
16
+ }
17
+ static update(arg) {
18
+ self[ListenFlagKey] ? (arg?.enableTweetDetected && (self[ListenFlagKey].enableTweetDetected = !0), arg?.enableUserDetected && (self[ListenFlagKey].enableUserDetected = !0)) : Object.defineProperty(self, ListenFlagKey, {
19
+ value: { ...arg },
20
+ enumerable: !1,
21
+ configurable: !1,
22
+ writable: !1
23
+ }), this.#flag = self[ListenFlagKey];
24
+ }
25
+ }
26
+ const timelineRegex = /TweetDetail|Timeline|Bookmarks|UserTweets|UserMedia|Likes/, id = "__listen-tweet-interceptor";
27
+ function listenNet() {
28
+ addXhrInterceptor({
29
+ id,
30
+ before: (url) => timelineRegex.test(url) ? url : void 0,
31
+ after: (text) => {
32
+ const json = JSON.parse(text), { tweets, users, videos } = XParser.parseSimple(json);
33
+ if (videos?.length) try {
34
+ trigger(ListenTweetEvents.VideoDetected, { detail: videos });
35
+ } catch {
36
+ }
37
+ const flag = ListenFlag.flag || {};
38
+ if (flag.enableTweetDetected && tweets?.length) try {
39
+ trigger(ListenTweetEvents.UserDetected, { detail: tweets });
40
+ } catch {
41
+ }
42
+ if (flag.enableUserDetected && users?.length) try {
43
+ trigger(ListenTweetEvents.UserDetected, { detail: users });
44
+ } catch {
45
+ }
46
+ }
47
+ });
48
+ }
49
+ const containerSelector = "main,main *", regionSelector = 'main [data-testid="primaryColumn"] [role="region"]', cellSelector = `${regionSelector} [data-testid="cellInnerDiv"]`, itemSelector = `${cellSelector} [role="listitem"]`, tweetSelector = [cellSelector, itemSelector].join(",");
50
+ function addedElements(els) {
51
+ const tweets = [];
52
+ function processTarget(el) {
53
+ if (el.matches(tweetSelector)) {
54
+ const id2 = getTweetId(el);
55
+ id2 && tweets.push(id2);
56
+ } else el.matches(containerSelector) && el.clientHeight > 300 && els.push(...el.querySelectorAll(tweetSelector));
57
+ }
58
+ for (let i = 0; i < els.length; i++)
59
+ try {
60
+ processTarget(els[i]);
61
+ } catch (e) {
62
+ console.warn(e);
63
+ }
64
+ tweets.length && trigger(ListenTweetEvents.TweetRendered, { detail: tweets });
65
+ }
66
+ function observePage() {
67
+ observe({ subtree: !0, addedElements });
68
+ }
69
+ function startListen(option) {
70
+ ListenFlag.isInit(option) || (listenNet(), observePage());
71
+ }
72
+ export {
73
+ startListen
74
+ };