/ clis / reddit / upvote.js
upvote.js
 1  import { CommandExecutionError } from '@jackwener/opencli/errors';
 2  import { cli, Strategy } from '@jackwener/opencli/registry';
 3  cli({
 4      site: 'reddit',
 5      name: 'upvote',
 6      description: 'Upvote or downvote a Reddit post',
 7      domain: 'reddit.com',
 8      strategy: Strategy.COOKIE,
 9      browser: true,
10      args: [
11          { name: 'post-id', type: 'string', required: true, positional: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
12          { name: 'direction', type: 'string', default: 'up', help: 'Vote direction: up, down, none' },
13      ],
14      columns: ['status', 'message'],
15      func: async (page, kwargs) => {
16          if (!page)
17              throw new CommandExecutionError('Browser session required');
18          await page.goto('https://www.reddit.com');
19          const result = await page.evaluate(`(async () => {
20        try {
21          let postId = ${JSON.stringify(kwargs['post-id'])};
22          // Extract ID from URL if needed
23          const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
24          if (urlMatch) postId = urlMatch[1];
25          // Build fullname
26          const fullname = postId.startsWith('t3_') || postId.startsWith('t1_')
27            ? postId : 't3_' + postId;
28  
29          const dir = ${JSON.stringify(kwargs.direction)};
30          const direction = dir === 'down' ? -1 : dir === 'none' ? 0 : 1;
31  
32          // Get modhash from Reddit config
33          const configEl = document.getElementById('config');
34          let modhash = '';
35          if (configEl) {
36            modhash = configEl.querySelector('[name="uh"]')?.getAttribute('content') || '';
37          }
38          if (!modhash) {
39            // Try fetching from /api/me.json
40            const meRes = await fetch('/api/me.json', { credentials: 'include' });
41            const me = await meRes.json();
42            modhash = me?.data?.modhash || '';
43          }
44  
45          const res = await fetch('/api/vote', {
46            method: 'POST',
47            credentials: 'include',
48            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
49            body: 'id=' + encodeURIComponent(fullname)
50              + '&dir=' + direction
51              + (modhash ? '&uh=' + encodeURIComponent(modhash) : ''),
52          });
53  
54          if (!res.ok) return { ok: false, message: 'HTTP ' + res.status };
55  
56          const labels = { '1': 'Upvoted', '-1': 'Downvoted', '0': 'Vote removed' };
57          return { ok: true, message: (labels[String(direction)] || 'Voted') + ' ' + fullname };
58        } catch (e) {
59          return { ok: false, message: e.toString() };
60        }
61      })()`);
62          return [{ status: result.ok ? 'success' : 'failed', message: result.message }];
63      }
64  });