web2cli 0.2.0__py3-none-any.whl

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 (44) hide show
  1. web2cli/__init__.py +3 -0
  2. web2cli/__main__.py +5 -0
  3. web2cli/adapter/__init__.py +0 -0
  4. web2cli/adapter/lint.py +667 -0
  5. web2cli/adapter/loader.py +157 -0
  6. web2cli/adapter/validator.py +127 -0
  7. web2cli/adapters/discord.com/web2cli.yaml +476 -0
  8. web2cli/adapters/mail.google.com/parsers/inbox.py +200 -0
  9. web2cli/adapters/mail.google.com/web2cli.yaml +52 -0
  10. web2cli/adapters/news.ycombinator.com/web2cli.yaml +356 -0
  11. web2cli/adapters/reddit.com/web2cli.yaml +233 -0
  12. web2cli/adapters/slack.com/web2cli.yaml +445 -0
  13. web2cli/adapters/stackoverflow.com/web2cli.yaml +257 -0
  14. web2cli/adapters/x.com/providers/x_graphql.py +299 -0
  15. web2cli/adapters/x.com/web2cli.yaml +449 -0
  16. web2cli/auth/__init__.py +0 -0
  17. web2cli/auth/browser_login.py +820 -0
  18. web2cli/auth/manager.py +166 -0
  19. web2cli/auth/store.py +68 -0
  20. web2cli/cli.py +1286 -0
  21. web2cli/executor/__init__.py +0 -0
  22. web2cli/executor/http.py +113 -0
  23. web2cli/output/__init__.py +0 -0
  24. web2cli/output/formatter.py +116 -0
  25. web2cli/parser/__init__.py +0 -0
  26. web2cli/parser/custom.py +21 -0
  27. web2cli/parser/html_parser.py +111 -0
  28. web2cli/parser/transforms.py +127 -0
  29. web2cli/pipe.py +10 -0
  30. web2cli/providers/__init__.py +6 -0
  31. web2cli/providers/base.py +22 -0
  32. web2cli/providers/registry.py +86 -0
  33. web2cli/runtime/__init__.py +1 -0
  34. web2cli/runtime/cache.py +42 -0
  35. web2cli/runtime/engine.py +743 -0
  36. web2cli/runtime/parser.py +398 -0
  37. web2cli/runtime/template.py +52 -0
  38. web2cli/types.py +71 -0
  39. web2cli-0.2.0.dist-info/METADATA +467 -0
  40. web2cli-0.2.0.dist-info/RECORD +44 -0
  41. web2cli-0.2.0.dist-info/WHEEL +5 -0
  42. web2cli-0.2.0.dist-info/entry_points.txt +2 -0
  43. web2cli-0.2.0.dist-info/licenses/LICENSE +202 -0
  44. web2cli-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,52 @@
1
+ meta:
2
+ spec_version: "0.2"
3
+ name: gmail
4
+ domain: mail.google.com
5
+ base_url: https://mail.google.com
6
+ version: 0.1.0
7
+ description: "Gmail — read your inbox from the terminal"
8
+ author: web2cli-core
9
+ transport: http
10
+ impersonate: chrome
11
+ aliases:
12
+ - gmail
13
+ default_headers:
14
+ User-Agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
15
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
16
+ Accept-Language: "en-US,en;q=0.9"
17
+
18
+ auth:
19
+ methods:
20
+ - type: cookies
21
+ keys: [SID, HSID, SSID, OSID]
22
+ env_var: WEB2CLI_GMAIL_COOKIES
23
+
24
+ commands:
25
+ inbox:
26
+ description: "List inbox threads (latest 50)"
27
+ args:
28
+ limit:
29
+ type: int
30
+ required: false
31
+ default: 20
32
+ max: 50
33
+ description: "Number of threads to show"
34
+ pipeline:
35
+ - request:
36
+ name: fetch
37
+ method: GET
38
+ url: /mail/u/0/
39
+ - parse:
40
+ name: parsed
41
+ from: fetch
42
+ parser: custom
43
+ script: parsers/inbox.py
44
+ - transform:
45
+ name: result
46
+ from: parsed
47
+ ops:
48
+ - limit: "{{args.limit}}"
49
+ output:
50
+ from_step: result
51
+ default_fields: [date, unread, sender_name, subject]
52
+ default_format: table
@@ -0,0 +1,356 @@
1
+ meta:
2
+ spec_version: "0.2"
3
+ name: hn
4
+ domain: news.ycombinator.com
5
+ base_url: https://hacker-news.firebaseio.com/v0
6
+ version: 0.2.0
7
+ description: "Hacker News — top stories, new, search, item, saved, upvoted"
8
+ author: web2cli-core
9
+ transport: http
10
+ aliases:
11
+ - hn
12
+ default_headers:
13
+ User-Agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
14
+
15
+ auth:
16
+ methods:
17
+ - type: cookies
18
+ keys: ["user"]
19
+ env_var: WEB2CLI_HN_COOKIES
20
+
21
+ commands:
22
+ top:
23
+ description: "Get top stories from Hacker News"
24
+ args:
25
+ limit:
26
+ type: int
27
+ required: false
28
+ default: 20
29
+ max: 200
30
+ description: "Number of stories to show"
31
+ pipeline:
32
+ - request:
33
+ name: ids
34
+ method: GET
35
+ url: /topstories.json
36
+ - fanout:
37
+ name: items
38
+ items_from: "{{steps.ids.json}}"
39
+ limit: "{{args.limit}}"
40
+ request:
41
+ method: GET
42
+ url: /item/{{item}}.json
43
+ - parse:
44
+ name: parsed
45
+ from: items
46
+ format: json_list
47
+ fields:
48
+ - name: rank
49
+ from: "$.__index"
50
+ - name: title
51
+ from: "$.title"
52
+ - name: score
53
+ from: "$.score"
54
+ - name: author
55
+ from: "$.by"
56
+ - name: comments
57
+ from: "$.descendants"
58
+ - name: url
59
+ from: "$.url"
60
+ - name: id
61
+ from: "$.id"
62
+ - name: hn_url
63
+ from: "$.id"
64
+ template: "https://news.ycombinator.com/item?id={{value}}"
65
+ output:
66
+ from_step: parsed
67
+ default_fields: [rank, title, score, comments, url]
68
+ default_format: table
69
+
70
+ new:
71
+ description: "Get newest stories"
72
+ args:
73
+ limit:
74
+ type: int
75
+ required: false
76
+ default: 20
77
+ max: 200
78
+ description: "Number of stories to show"
79
+ pipeline:
80
+ - request:
81
+ name: ids
82
+ method: GET
83
+ url: /newstories.json
84
+ - fanout:
85
+ name: items
86
+ items_from: "{{steps.ids.json}}"
87
+ limit: "{{args.limit}}"
88
+ request:
89
+ method: GET
90
+ url: /item/{{item}}.json
91
+ - parse:
92
+ name: parsed
93
+ from: items
94
+ format: json_list
95
+ fields:
96
+ - name: rank
97
+ from: "$.__index"
98
+ - name: title
99
+ from: "$.title"
100
+ - name: score
101
+ from: "$.score"
102
+ - name: author
103
+ from: "$.by"
104
+ - name: comments
105
+ from: "$.descendants"
106
+ - name: url
107
+ from: "$.url"
108
+ - name: id
109
+ from: "$.id"
110
+ - name: hn_url
111
+ from: "$.id"
112
+ template: "https://news.ycombinator.com/item?id={{value}}"
113
+ output:
114
+ from_step: parsed
115
+ default_fields: [rank, title, score, author, url]
116
+ default_format: table
117
+
118
+ item:
119
+ description: "Get a single HN item (story, comment, job)"
120
+ args:
121
+ id:
122
+ type: string
123
+ required: true
124
+ source: [arg, stdin]
125
+ description: "HN item ID"
126
+ pipeline:
127
+ - request:
128
+ name: fetch
129
+ method: GET
130
+ url: /item/{{args.id}}.json
131
+ - parse:
132
+ name: parsed
133
+ from: fetch
134
+ format: json
135
+ extract: "$"
136
+ fields:
137
+ - name: id
138
+ from: "$.id"
139
+ - name: title
140
+ from: "$.title"
141
+ - name: author
142
+ from: "$.by"
143
+ - name: score
144
+ from: "$.score"
145
+ - name: url
146
+ from: "$.url"
147
+ - name: text
148
+ from: "$.text"
149
+ transform: strip_html
150
+ - name: time
151
+ from: "$.time"
152
+ transform: timestamp
153
+ - name: comments
154
+ from: "$.descendants"
155
+ output:
156
+ from_step: parsed
157
+ default_fields: [title, author, score, url, time]
158
+ default_format: table
159
+
160
+ search:
161
+ description: "Search HN stories (via Algolia)"
162
+ args:
163
+ query:
164
+ type: string
165
+ required: true
166
+ source: [arg, stdin]
167
+ description: "Search query"
168
+ limit:
169
+ type: int
170
+ required: false
171
+ default: 20
172
+ pipeline:
173
+ - request:
174
+ name: fetch
175
+ method: GET
176
+ url: https://hn.algolia.com/api/v1/search
177
+ params:
178
+ query: "{{args.query}}"
179
+ tags: story
180
+ hitsPerPage: "{{args.limit}}"
181
+ - parse:
182
+ name: parsed
183
+ from: fetch
184
+ format: json
185
+ extract: "$.hits[*]"
186
+ fields:
187
+ - name: title
188
+ from: "$.title"
189
+ - name: author
190
+ from: "$.author"
191
+ - name: score
192
+ from: "$.points"
193
+ - name: comments
194
+ from: "$.num_comments"
195
+ - name: url
196
+ from: "$.url"
197
+ - name: date
198
+ from: "$.created_at"
199
+ transform: timestamp
200
+ - name: hn_url
201
+ from: "$.objectID"
202
+ template: "https://news.ycombinator.com/item?id={{value}}"
203
+ output:
204
+ from_step: parsed
205
+ default_fields: [title, score, comments, url]
206
+ default_format: table
207
+
208
+ saved:
209
+ description: "Get saved stories (requires login)"
210
+ args:
211
+ username:
212
+ type: string
213
+ required: true
214
+ description: "HN username"
215
+ pipeline:
216
+ - request:
217
+ name: fetch
218
+ method: GET
219
+ url: https://news.ycombinator.com/favorites?id={{args.username}}
220
+ - parse:
221
+ name: parsed
222
+ from: fetch
223
+ format: html
224
+ extract: "tr.athing"
225
+ fields:
226
+ - name: rank
227
+ path: "span.rank"
228
+ attribute: text
229
+ transform: int
230
+ - name: title
231
+ path: "span.titleline > a"
232
+ attribute: text
233
+ - name: url
234
+ path: "span.titleline > a"
235
+ attribute: href
236
+ - name: score
237
+ relative: next
238
+ path: "span.score"
239
+ attribute: text
240
+ transform: int
241
+ - name: author
242
+ relative: next
243
+ path: "a.hnuser"
244
+ attribute: text
245
+ - name: comments
246
+ relative: next
247
+ path: "a:last-of-type"
248
+ attribute: text
249
+ - name: age
250
+ relative: next
251
+ path: "span.age"
252
+ attribute: text
253
+ output:
254
+ from_step: parsed
255
+ default_fields: [title, score, author, comments, url]
256
+ default_format: table
257
+
258
+ upvoted:
259
+ description: "Get upvoted stories (requires login)"
260
+ args:
261
+ username:
262
+ type: string
263
+ required: true
264
+ description: "HN username"
265
+ pipeline:
266
+ - request:
267
+ name: fetch
268
+ method: GET
269
+ url: https://news.ycombinator.com/upvoted?id={{args.username}}
270
+ - parse:
271
+ name: parsed
272
+ from: fetch
273
+ format: html
274
+ extract: "tr.athing"
275
+ fields:
276
+ - name: rank
277
+ path: "span.rank"
278
+ attribute: text
279
+ transform: int
280
+ - name: title
281
+ path: "span.titleline > a"
282
+ attribute: text
283
+ - name: url
284
+ path: "span.titleline > a"
285
+ attribute: href
286
+ - name: score
287
+ relative: next
288
+ path: "span.score"
289
+ attribute: text
290
+ transform: int
291
+ - name: author
292
+ relative: next
293
+ path: "a.hnuser"
294
+ attribute: text
295
+ - name: comments
296
+ relative: next
297
+ path: "a:last-of-type"
298
+ attribute: text
299
+ - name: age
300
+ relative: next
301
+ path: "span.age"
302
+ attribute: text
303
+ output:
304
+ from_step: parsed
305
+ default_fields: [title, score, author, comments, url]
306
+ default_format: table
307
+
308
+ submissions:
309
+ description: "Get a user's submissions"
310
+ args:
311
+ username:
312
+ type: string
313
+ required: true
314
+ description: "HN username"
315
+ pipeline:
316
+ - request:
317
+ name: fetch
318
+ method: GET
319
+ url: https://news.ycombinator.com/submitted?id={{args.username}}
320
+ - parse:
321
+ name: parsed
322
+ from: fetch
323
+ format: html
324
+ extract: "tr.athing"
325
+ fields:
326
+ - name: rank
327
+ path: "span.rank"
328
+ attribute: text
329
+ transform: int
330
+ - name: title
331
+ path: "span.titleline > a"
332
+ attribute: text
333
+ - name: url
334
+ path: "span.titleline > a"
335
+ attribute: href
336
+ - name: score
337
+ relative: next
338
+ path: "span.score"
339
+ attribute: text
340
+ transform: int
341
+ - name: author
342
+ relative: next
343
+ path: "a.hnuser"
344
+ attribute: text
345
+ - name: comments
346
+ relative: next
347
+ path: "a:last-of-type"
348
+ attribute: text
349
+ - name: age
350
+ relative: next
351
+ path: "span.age"
352
+ attribute: text
353
+ output:
354
+ from_step: parsed
355
+ default_fields: [title, score, comments, age, url]
356
+ default_format: table
@@ -0,0 +1,233 @@
1
+ meta:
2
+ spec_version: "0.2"
3
+ name: reddit
4
+ domain: reddit.com
5
+ base_url: https://www.reddit.com
6
+ version: 0.2.0
7
+ description: "Reddit — posts, threads, search"
8
+ author: web2cli-core
9
+ transport: http
10
+ aliases:
11
+ - reddit
12
+ default_headers:
13
+ User-Agent: "web2cli/0.2"
14
+
15
+ commands:
16
+ posts:
17
+ description: "List posts from a subreddit"
18
+ args:
19
+ sub:
20
+ type: string
21
+ required: true
22
+ source: [arg, stdin]
23
+ description: "Subreddit name (e.g. programming, python)"
24
+ sort:
25
+ type: string
26
+ required: false
27
+ default: hot
28
+ description: "Sort: hot, new, top, rising"
29
+ limit:
30
+ type: int
31
+ required: false
32
+ default: 20
33
+ description: "Number of posts"
34
+ time:
35
+ type: string
36
+ required: false
37
+ description: "Time filter for top sort: hour, day, week, month, year, all"
38
+ pipeline:
39
+ - request:
40
+ name: fetch
41
+ method: GET
42
+ url: /r/{{args.sub}}/{{args.sort}}.json
43
+ params:
44
+ limit: "{{args.limit}}"
45
+ t: "{{args.time}}"
46
+ - parse:
47
+ name: parsed
48
+ from: fetch
49
+ format: json
50
+ extract: "$.data.children[*]"
51
+ fields:
52
+ - name: id
53
+ from: $.data.id
54
+ - name: title
55
+ from: "$.data.title"
56
+ - name: author
57
+ from: "$.data.author"
58
+ - name: score
59
+ from: "$.data.score"
60
+ - name: comments
61
+ from: "$.data.num_comments"
62
+ - name: sub
63
+ from: "$.data.subreddit"
64
+ - name: url
65
+ from: "$.data.url"
66
+ - name: date
67
+ from: "$.data.created_utc"
68
+ transform: timestamp
69
+ - name: ratio
70
+ from: "$.data.upvote_ratio"
71
+ - name: permalink
72
+ from: "$.data.permalink"
73
+ template: "https://reddit.com{{value}}"
74
+ output:
75
+ from_step: parsed
76
+ default_fields: [id, title, score, comments, author, date]
77
+ default_format: table
78
+
79
+ thread:
80
+ description: "Get a thread with comments"
81
+ args:
82
+ id:
83
+ type: string
84
+ required: true
85
+ source: [arg, stdin]
86
+ description: "Thread ID (e.g. 1qoxwdt)"
87
+ limit:
88
+ type: int
89
+ required: false
90
+ default: 20
91
+ description: "Number of top-level comments"
92
+ sort:
93
+ type: string
94
+ required: false
95
+ default: best
96
+ description: "Sort: best, top, new, old, controversial"
97
+ pipeline:
98
+ - request:
99
+ name: fetch
100
+ method: GET
101
+ url: /comments/{{args.id}}.json
102
+ params:
103
+ limit: "{{args.limit}}"
104
+ sort: "{{args.sort}}"
105
+ - parse:
106
+ name: post
107
+ from: fetch
108
+ format: json
109
+ extract: "$[0].data.children[0].data"
110
+ fields:
111
+ - name: author
112
+ from: "$.author"
113
+ - name: text
114
+ from:
115
+ coalesce:
116
+ - "$.selftext"
117
+ - "$.url"
118
+ - ""
119
+ ops:
120
+ - template:
121
+ value: "[POST] {{item.title}}\n{{value}}"
122
+ - regex_replace:
123
+ pattern: "\\n$"
124
+ repl: ""
125
+ - name: score
126
+ from: "$.score"
127
+ - name: date
128
+ from: "$.created_utc"
129
+ transform: timestamp
130
+ - parse:
131
+ name: comments
132
+ from: fetch
133
+ format: json
134
+ extract: "$[1].data.children[*]"
135
+ item_ops:
136
+ - flatten_tree:
137
+ include_path: "$.kind"
138
+ include_equals: t1
139
+ children_path: "$.data.replies.data.children[*]"
140
+ item_path: "$.data"
141
+ depth_path: "$.depth"
142
+ depth_field: "__depth"
143
+ indent_field: "__indent"
144
+ indent_unit: " "
145
+ fields:
146
+ - name: depth
147
+ from: "$.__depth"
148
+ - name: author
149
+ from: "$.author"
150
+ ops:
151
+ - template:
152
+ value: "{{item.__indent}}{{value}}"
153
+ - name: text
154
+ from: "$.body"
155
+ - name: score
156
+ from: "$.score"
157
+ - name: date
158
+ from: "$.created_utc"
159
+ transform: timestamp
160
+ - transform:
161
+ name: parsed
162
+ from: comments
163
+ ops:
164
+ - concat:
165
+ steps: [post]
166
+ position: before
167
+ output:
168
+ from_step: parsed
169
+ default_fields: [author, text, score, date, depth]
170
+ default_format: table
171
+
172
+ search:
173
+ description: "Search posts in a subreddit"
174
+ args:
175
+ sub:
176
+ type: string
177
+ required: true
178
+ description: "Subreddit to search in"
179
+ query:
180
+ type: string
181
+ required: true
182
+ source: [arg, stdin]
183
+ description: "Search query"
184
+ limit:
185
+ type: int
186
+ required: false
187
+ default: 20
188
+ description: "Number of results"
189
+ sort:
190
+ type: string
191
+ required: false
192
+ default: relevance
193
+ description: "Sort: relevance, hot, top, new, comments"
194
+ pipeline:
195
+ - request:
196
+ name: fetch
197
+ method: GET
198
+ url: /r/{{args.sub}}/search.json
199
+ params:
200
+ q: "{{args.query}}"
201
+ limit: "{{args.limit}}"
202
+ sort: "{{args.sort}}"
203
+ restrict_sr: "on"
204
+ - parse:
205
+ name: parsed
206
+ from: fetch
207
+ format: json
208
+ extract: "$.data.children[*]"
209
+ fields:
210
+ - name: id
211
+ from: "$.data.id"
212
+ - name: title
213
+ from: "$.data.title"
214
+ - name: author
215
+ from: "$.data.author"
216
+ - name: score
217
+ from: "$.data.score"
218
+ - name: comments
219
+ from: "$.data.num_comments"
220
+ - name: sub
221
+ from: "$.data.subreddit"
222
+ - name: url
223
+ from: "$.data.url"
224
+ - name: date
225
+ from: "$.data.created_utc"
226
+ transform: timestamp
227
+ - name: permalink
228
+ from: "$.data.permalink"
229
+ template: "https://reddit.com{{value}}"
230
+ output:
231
+ from_step: parsed
232
+ default_fields: [id, title, score, comments, author, date]
233
+ default_format: table