fastbrowser_cli 1.0.35 → 1.0.39
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/README.md +26 -5
- package/dist/contribs/_shared/fastbrowser_helper.d.ts +13 -0
- package/dist/contribs/_shared/fastbrowser_helper.d.ts.map +1 -0
- package/dist/contribs/_shared/fastbrowser_helper.js +39 -0
- package/dist/contribs/_shared/fastbrowser_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/cli.d.ts +3 -0
- package/dist/contribs/linkedin_cli/src/cli.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/cli.js +299 -0
- package/dist/contribs/linkedin_cli/src/cli.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.d.ts +73 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.js +866 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.d.ts +61 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.js +885 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.d.ts +11 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.js +145 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/cli.d.ts +3 -0
- package/dist/contribs/twitter_cli/src/cli.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/cli.js +273 -0
- package/dist/contribs/twitter_cli/src/cli.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.d.ts +28 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.js +274 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.d.ts +43 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.js +519 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.d.ts +11 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.js +213 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.js.map +1 -0
- package/dist/fastbrowser_cli/fastbrowser_cli.js +43 -0
- package/dist/fastbrowser_cli/fastbrowser_cli.js.map +1 -1
- package/dist/fastbrowser_httpd/libs/tool-schemas.d.ts +4 -0
- package/dist/fastbrowser_httpd/libs/tool-schemas.d.ts.map +1 -1
- package/dist/fastbrowser_httpd/libs/tool-schemas.js +4 -0
- package/dist/fastbrowser_httpd/libs/tool-schemas.js.map +1 -1
- package/dist/fastbrowser_mcp/fastbrowser_mcp.js +36 -2
- package/dist/fastbrowser_mcp/fastbrowser_mcp.js.map +1 -1
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.d.ts +2 -0
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.d.ts.map +1 -1
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.js +12 -0
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.js.map +1 -1
- package/dist/fastbrowser_mcp/libs/response_formatter.d.ts +1 -0
- package/dist/fastbrowser_mcp/libs/response_formatter.d.ts.map +1 -1
- package/dist/fastbrowser_mcp/libs/response_formatter.js +27 -0
- package/dist/fastbrowser_mcp/libs/response_formatter.js.map +1 -1
- package/dist/shared/fastbrowser_helper.d.ts +13 -0
- package/dist/shared/fastbrowser_helper.d.ts.map +1 -0
- package/dist/shared/fastbrowser_helper.js +39 -0
- package/dist/shared/fastbrowser_helper.js.map +1 -0
- package/examples/linkedin_cli_TOREMOVE/README.md +7 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm.sh +40 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm.ts +326 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm_messages.ts +279 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_full_cycle.sh +5 -0
- package/examples/{linkedin_cli/linked_post.sh → linkedin_cli_TOREMOVE/linkedin_post.sh} +3 -0
- package/examples/linkedin_cli_TOREMOVE/message_thread.a11y.txt +252 -0
- package/examples/whatsapp/whatapp.a11y.txt +1521 -0
- package/examples/whatsapp/whatsapp.sh +10 -0
- package/listitem +7 -0
- package/package.json +7 -3
- package/skills/fastbrowser/SKILL.md +116 -29
- package/src/contribs/_shared/fastbrowser_helper.ts +49 -0
- package/src/contribs/linkedin_cli/README.md +80 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_jeromeetienne.a11y.txt +2364 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_jontwigge.a11y.txt +2740 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_julien_guezennec.a11y.txt +2073 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_jeromeetienne.a11y.txt +1863 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_jontwigge.a11y.txt +1738 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_julien_guezennec.a11y.txt +2182 -0
- package/src/contribs/linkedin_cli/src/cli.ts +345 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_profile_helper.ts +964 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.ts +982 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_thread_helper.ts +171 -0
- package/src/contribs/twitter_cli/README.md +79 -0
- package/src/contribs/twitter_cli/data/twitter_chat.a11y.txt +215 -0
- package/src/contribs/twitter_cli/data/twitter_home.a11y.txt +467 -0
- package/src/contribs/twitter_cli/data/twitter_profile.a11y.txt +418 -0
- package/src/contribs/twitter_cli/data/twitter_profile_jontwigge.a11y.txt +484 -0
- package/src/contribs/twitter_cli/data/twitter_profile_molokoloco.a11y.txt +483 -0
- package/src/contribs/twitter_cli/src/cli.ts +315 -0
- package/src/contribs/twitter_cli/src/libs/twitter_profile_helper.ts +328 -0
- package/src/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.ts +607 -0
- package/src/contribs/twitter_cli/src/libs/twitter_thread_helper.ts +240 -0
- package/src/fastbrowser_cli/fastbrowser_cli.ts +51 -0
- package/src/fastbrowser_httpd/libs/tool-schemas.ts +6 -0
- package/src/fastbrowser_mcp/fastbrowser_mcp.ts +46 -3
- package/src/fastbrowser_mcp/libs/mcp_target_helper.ts +11 -0
- package/src/fastbrowser_mcp/libs/response_formatter.ts +29 -0
- package/src/shared/fastbrowser_helper.ts +49 -0
- package/tsconfig.json +1 -1
- package/examples/linkedin_cli/linked_dm.sh +0 -19
- package/examples/mcp_client_playwright.ts +0 -34
- /package/examples/{linkedin_cli → linkedin_cli_TOREMOVE}/linkedin.snapshot.txt +0 -0
- /package/examples/{twitter_cli → twitter_cli_TOREMOVE}/twitter_post.sh +0 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
|
|
3
|
+
// npm imports
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { A11yQuery, A11yTree, AxNode } from 'a11y_parse';
|
|
6
|
+
|
|
7
|
+
// local imports
|
|
8
|
+
import { FastBrowserHelper } from '../../_shared/fastbrowser_helper.js';
|
|
9
|
+
import { LinkedinThreadHelper } from './libs/linkedin_thread_helper.js';
|
|
10
|
+
import { LinkedinProfile, LinkedinProfileHelper } from './libs/linkedin_profile_helper.js';
|
|
11
|
+
import { LinkedinPost, LinkedinRecentPostsHelper } from './libs/linkedin_recent_posts_helper.js';
|
|
12
|
+
|
|
13
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
15
|
+
//
|
|
16
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
17
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
18
|
+
|
|
19
|
+
class MainHelper {
|
|
20
|
+
|
|
21
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
//
|
|
24
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
25
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
26
|
+
|
|
27
|
+
static async gotoPageMessaging(): Promise<void> {
|
|
28
|
+
await FastBrowserHelper.run('check');
|
|
29
|
+
await FastBrowserHelper.navigatePage('https://www.linkedin.com/messaging/');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
33
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
34
|
+
//
|
|
35
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
36
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
37
|
+
|
|
38
|
+
static async gotoPageFeed(): Promise<void> {
|
|
39
|
+
await FastBrowserHelper.run('check');
|
|
40
|
+
await FastBrowserHelper.navigatePage('https://www.linkedin.com/feed/');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
44
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
45
|
+
//
|
|
46
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
47
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
48
|
+
|
|
49
|
+
static async gotoPageProfile(slug: string): Promise<void> {
|
|
50
|
+
if (slug.length === 0) {
|
|
51
|
+
throw new Error('slug is required');
|
|
52
|
+
}
|
|
53
|
+
await FastBrowserHelper.run('check');
|
|
54
|
+
await FastBrowserHelper.navigatePage(`https://www.linkedin.com/in/${slug}/`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
58
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
59
|
+
//
|
|
60
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
61
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
62
|
+
|
|
63
|
+
static async gotoPageRecentPosts(slug: string): Promise<void> {
|
|
64
|
+
if (slug.length === 0) {
|
|
65
|
+
throw new Error('slug is required');
|
|
66
|
+
}
|
|
67
|
+
await FastBrowserHelper.run('check');
|
|
68
|
+
await FastBrowserHelper.navigatePage(`https://www.linkedin.com/in/${slug}/recent-activity/all/`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
72
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
73
|
+
//
|
|
74
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
75
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
76
|
+
|
|
77
|
+
static async exportRecentPosts(slug: string, limit: number): Promise<LinkedinPost[]> {
|
|
78
|
+
// Trigger LinkedIn's infinite-scroll inside the window so that more than the initial posts get rendered.
|
|
79
|
+
const scrollFunctionTxt = [
|
|
80
|
+
`() => {`,
|
|
81
|
+
` const tryCount = 6;`,
|
|
82
|
+
` const delayMs = 500;`,
|
|
83
|
+
` (async () => {`,
|
|
84
|
+
` for (let i = 0; i < tryCount; i++) {`,
|
|
85
|
+
` window.scrollTo({`,
|
|
86
|
+
` top: 600000,`,
|
|
87
|
+
` behavior: 'smooth'`,
|
|
88
|
+
` });`,
|
|
89
|
+
` await new Promise(resolve => setTimeout(resolve, delayMs));`,
|
|
90
|
+
` }`,
|
|
91
|
+
` })();`,
|
|
92
|
+
`}`,
|
|
93
|
+
].join('\n');
|
|
94
|
+
await FastBrowserHelper.evaluateScript(scrollFunctionTxt);
|
|
95
|
+
|
|
96
|
+
// take snapshot and parse posts
|
|
97
|
+
const snapshot = await FastBrowserHelper.takeSnapshot();
|
|
98
|
+
let posts: LinkedinPost[] = LinkedinRecentPostsHelper.parsePosts(snapshot, slug);
|
|
99
|
+
// apply limit
|
|
100
|
+
if (limit > 0 && posts.length > limit) {
|
|
101
|
+
posts = posts.slice(0, limit);
|
|
102
|
+
}
|
|
103
|
+
// return posts
|
|
104
|
+
return posts;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
108
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
109
|
+
//
|
|
110
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
111
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
112
|
+
|
|
113
|
+
static async exportProfile(slug: string): Promise<LinkedinProfile> {
|
|
114
|
+
// scroll to the bottom of the page multiple times to load dynamic content (like experience details, recommendations, etc.)
|
|
115
|
+
const functionTxt = [
|
|
116
|
+
`() => {`,
|
|
117
|
+
` // select the element`,
|
|
118
|
+
` const workspace = document.querySelector('main#workspace');`,
|
|
119
|
+
` if (workspace === null) {`,
|
|
120
|
+
` throw new Error('Workspace element not found');`,
|
|
121
|
+
` }`,
|
|
122
|
+
` // scroll to the bottom of the page multiple times to load dynamic content (like experience details, recommendations, etc.)`,
|
|
123
|
+
` const tryCount = 6;`,
|
|
124
|
+
` const delayMs = 500;`,
|
|
125
|
+
` (async () => {`,
|
|
126
|
+
` for (let i = 0; i < tryCount; i++) {`,
|
|
127
|
+
` workspace.scrollBy({`,
|
|
128
|
+
` top: 600000,`,
|
|
129
|
+
` behavior: 'smooth'`,
|
|
130
|
+
` });`,
|
|
131
|
+
` await new Promise(resolve => setTimeout(resolve, delayMs));`,
|
|
132
|
+
` }`,
|
|
133
|
+
` resolve(true);`,
|
|
134
|
+
` })();`,
|
|
135
|
+
`}`,
|
|
136
|
+
].join('\n');
|
|
137
|
+
const resultEvaluateStr: string = await FastBrowserHelper.evaluateScript(functionTxt);
|
|
138
|
+
|
|
139
|
+
// Take snapshot
|
|
140
|
+
const snapshot = await FastBrowserHelper.takeSnapshot();
|
|
141
|
+
// Parse profile
|
|
142
|
+
const linkedinProfile = LinkedinProfileHelper.parseProfile(snapshot, slug);
|
|
143
|
+
// Return profile
|
|
144
|
+
return linkedinProfile;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
148
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
149
|
+
//
|
|
150
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
151
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
152
|
+
|
|
153
|
+
static async createPost(content: string): Promise<void> {
|
|
154
|
+
await FastBrowserHelper.click('button[name^="Start a post"]');
|
|
155
|
+
await FastBrowserHelper.fillForm('textbox[name^="Text editor"]', content);
|
|
156
|
+
await FastBrowserHelper.click('button[name^="Post"]');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
160
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
161
|
+
//
|
|
162
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
163
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
164
|
+
|
|
165
|
+
static async listConvoNames(): Promise<string[]> {
|
|
166
|
+
const output = await FastBrowserHelper.querySelectorsAll(
|
|
167
|
+
'list[name="Conversation List"] > listitem heading',
|
|
168
|
+
0,
|
|
169
|
+
);
|
|
170
|
+
const names: string[] = [];
|
|
171
|
+
for (const line of output.split('\n')) {
|
|
172
|
+
if (/^uid=\S+\s+heading\s+"/.test(line) === false) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const axNode = A11yTree.parse(line);
|
|
176
|
+
if (axNode.name === undefined) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
names.push(axNode.name);
|
|
180
|
+
}
|
|
181
|
+
return names;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
185
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
186
|
+
//
|
|
187
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
188
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
189
|
+
|
|
190
|
+
static async selectConversation(targetUser: string): Promise<void> {
|
|
191
|
+
const escaped = targetUser.replace(/"/g, '\\"');
|
|
192
|
+
await FastBrowserHelper.click(
|
|
193
|
+
`list[name="Conversation List"] > listitem heading[name^="${escaped}"]`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
198
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
199
|
+
//
|
|
200
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
201
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
202
|
+
|
|
203
|
+
static async fillAndSendMessage(message: string): Promise<void> {
|
|
204
|
+
await FastBrowserHelper.fillForm('textbox[name^="Write"]', message);
|
|
205
|
+
await FastBrowserHelper.click('button[name^="Send"]');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
209
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
210
|
+
//
|
|
211
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
212
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
213
|
+
|
|
214
|
+
static async getMessagesTranscript(): Promise<string> {
|
|
215
|
+
const output = await FastBrowserHelper.takeSnapshot();
|
|
216
|
+
const axTree = A11yTree.parse(output);
|
|
217
|
+
const threadNode = MainHelper.findThreadNode(axTree);
|
|
218
|
+
return await LinkedinThreadHelper.parseMessagesThread(threadNode);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
222
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
223
|
+
//
|
|
224
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
225
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
226
|
+
|
|
227
|
+
private static findThreadNode(axTree: AxNode): AxNode {
|
|
228
|
+
const convList = A11yQuery.querySelector(axTree, 'list[name="Conversation List"]');
|
|
229
|
+
if (convList === undefined) {
|
|
230
|
+
throw new Error('Could not find conversation list node');
|
|
231
|
+
}
|
|
232
|
+
const convListParent = convList.parent;
|
|
233
|
+
if (convListParent === undefined) {
|
|
234
|
+
throw new Error('Conversation list node has no parent');
|
|
235
|
+
}
|
|
236
|
+
const convDetails = A11yTree.nextSibling(convListParent);
|
|
237
|
+
if (convDetails === undefined) {
|
|
238
|
+
throw new Error('Could not find conversation details node');
|
|
239
|
+
}
|
|
240
|
+
const threadNode = A11yQuery.querySelector(convDetails, 'list');
|
|
241
|
+
if (threadNode === undefined) {
|
|
242
|
+
throw new Error('Could not find thread node');
|
|
243
|
+
}
|
|
244
|
+
return threadNode;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
249
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
250
|
+
// Entry point
|
|
251
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
252
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
253
|
+
|
|
254
|
+
async function main(): Promise<void> {
|
|
255
|
+
const program = new Command();
|
|
256
|
+
|
|
257
|
+
program
|
|
258
|
+
.name('linkedin_cli')
|
|
259
|
+
.description('LinkedIn DM CLI - command line tool to interact with LinkedIn using the FastBrowser CLI');
|
|
260
|
+
|
|
261
|
+
program
|
|
262
|
+
.command('post <content>')
|
|
263
|
+
.description('Create a post on the LinkedIn feed')
|
|
264
|
+
.action(async (content: string) => {
|
|
265
|
+
await MainHelper.gotoPageFeed();
|
|
266
|
+
await MainHelper.createPost(content);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
program
|
|
270
|
+
.command('dm_page')
|
|
271
|
+
.description('Navigate to the LinkedIn messaging page')
|
|
272
|
+
.action(async () => {
|
|
273
|
+
await MainHelper.gotoPageMessaging();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
program
|
|
277
|
+
.command('dm_list')
|
|
278
|
+
.description('List the names of people you have conversations with. (assume you did \'dm_page\' first)')
|
|
279
|
+
.action(async () => {
|
|
280
|
+
const names = await MainHelper.listConvoNames();
|
|
281
|
+
for (const name of names) {
|
|
282
|
+
console.log(name);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
program
|
|
287
|
+
.command('dm_send <target_user> <message>')
|
|
288
|
+
.description('Send a message in an existing conversation. (assume you did \'dm_page\' first)')
|
|
289
|
+
.action(async (targetUser: string, message: string) => {
|
|
290
|
+
await MainHelper.selectConversation(targetUser);
|
|
291
|
+
await MainHelper.fillAndSendMessage(message);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
program
|
|
295
|
+
.command('dm_thread <target_user>')
|
|
296
|
+
.description('Get the message thread of a conversation. (assume you did \'dm_page\' first)')
|
|
297
|
+
.action(async (targetUser: string) => {
|
|
298
|
+
await MainHelper.selectConversation(targetUser);
|
|
299
|
+
const transcript = await MainHelper.getMessagesTranscript();
|
|
300
|
+
console.log(transcript);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
program
|
|
304
|
+
.command('profile <slug>')
|
|
305
|
+
.description('Export a LinkedIn profile by slug (path component of /in/<slug>/)')
|
|
306
|
+
.option('-f, --format <format>', 'output format: markdown or json', 'markdown')
|
|
307
|
+
.action(async (slug: string, opts: { format: string; }) => {
|
|
308
|
+
if (opts.format !== 'markdown' && opts.format !== 'json') {
|
|
309
|
+
throw new Error(`unknown format '${opts.format}', expected 'markdown' or 'json'`);
|
|
310
|
+
}
|
|
311
|
+
await MainHelper.gotoPageProfile(slug);
|
|
312
|
+
const profile = await MainHelper.exportProfile(slug);
|
|
313
|
+
if (opts.format === 'json') {
|
|
314
|
+
console.log(JSON.stringify(profile));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
console.log(LinkedinProfileHelper.formatMarkdown(profile));
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
program
|
|
321
|
+
.command('recent_posts <slug>')
|
|
322
|
+
.description('Export the recent activity (posts) of a LinkedIn profile')
|
|
323
|
+
.option('-f, --format <format>', 'output format: markdown or json', 'markdown')
|
|
324
|
+
.option('-l, --limit <limit>', 'max number of posts to return (0 = all visible)', '0')
|
|
325
|
+
.action(async (slug: string, opts: { format: string; limit: string; }) => {
|
|
326
|
+
if (opts.format !== 'markdown' && opts.format !== 'json') {
|
|
327
|
+
throw new Error(`unknown format '${opts.format}', expected 'markdown' or 'json'`);
|
|
328
|
+
}
|
|
329
|
+
const limit = parseInt(opts.limit, 10);
|
|
330
|
+
if (Number.isNaN(limit) === true || limit < 0) {
|
|
331
|
+
throw new Error(`invalid limit '${opts.limit}', expected a non-negative integer`);
|
|
332
|
+
}
|
|
333
|
+
await MainHelper.gotoPageRecentPosts(slug);
|
|
334
|
+
const posts = await MainHelper.exportRecentPosts(slug, limit);
|
|
335
|
+
if (opts.format === 'json') {
|
|
336
|
+
console.log(JSON.stringify(posts));
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
console.log(LinkedinRecentPostsHelper.formatMarkdown(posts));
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
await program.parseAsync();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
void main();
|