-
-
Notifications
You must be signed in to change notification settings - Fork 89
Expand file tree
/
Copy pathdmManager.js
More file actions
141 lines (115 loc) · 5 KB
/
Copy pathdmManager.js
File metadata and controls
141 lines (115 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright (c) 2024-2026 nich (@nichxbt). Licensed under the Apache License, Version 2.0.
// scripts/dmManager.js
// Browser console script for sending DMs and exporting conversations on X/Twitter
// Paste in DevTools console on x.com/messages
// by nichxbt
(() => {
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
// =============================================
// CONFIGURATION
// =============================================
const CONFIG = {
action: 'send', // 'send' | 'export'
targetUser: '', // Username to DM (for 'send')
message: '', // Message to send
maxConversations: 20, // Max conversations to export
scrollDelay: 1500,
dryRun: true, // SET FALSE TO EXECUTE
};
// =============================================
const download = (data, filename) => {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }));
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
console.log(`📥 Downloaded: ${filename}`);
};
const sendDM = async () => {
if (!CONFIG.targetUser || !CONFIG.message) {
console.error('❌ Set CONFIG.targetUser and CONFIG.message first!');
return;
}
console.log(`💬 Sending DM to @${CONFIG.targetUser}...`);
if (CONFIG.dryRun) {
console.log(` 📝 Would send to @${CONFIG.targetUser}: "${CONFIG.message.substring(0, 80)}..."`);
return;
}
try {
// Click new DM
const newBtn = document.querySelector('[data-testid="NewDM_Button"]');
if (newBtn) { newBtn.click(); await sleep(1500); }
// Search user
const searchInput = document.querySelector('[data-testid="searchPeople"]');
if (!searchInput) { console.error('❌ Search input not found'); return; }
searchInput.focus();
document.execCommand('insertText', false, CONFIG.targetUser);
await sleep(2000);
// Select user
const cells = document.querySelectorAll('[data-testid="TypeaheadUser"], [data-testid="UserCell"]');
let found = false;
for (const cell of cells) {
if (cell.textContent.toLowerCase().includes(CONFIG.targetUser.toLowerCase())) {
cell.click();
found = true;
break;
}
}
if (!found) { console.error(`❌ @${CONFIG.targetUser} not found`); return; }
await sleep(1000);
// Click next
const nextBtn = document.querySelector('[data-testid="nextButton"]');
if (nextBtn) { nextBtn.click(); await sleep(1500); }
// Type and send
const msgInput = document.querySelector('[data-testid="dmComposerTextInput"]');
if (msgInput) {
msgInput.focus();
document.execCommand('insertText', false, CONFIG.message);
await sleep(500);
const sendBtn = document.querySelector('[data-testid="dmComposerSendButton"]');
if (sendBtn) { sendBtn.click(); await sleep(1000); }
}
console.log(`✅ DM sent to @${CONFIG.targetUser}`);
} catch (e) {
console.error('❌ Failed to send DM:', e.message);
}
};
const exportConversations = async () => {
console.log(`📥 Exporting up to ${CONFIG.maxConversations} conversations...`);
const conversations = [];
let retries = 0;
while (conversations.length < CONFIG.maxConversations && retries < 5) {
const prevSize = conversations.length;
document.querySelectorAll('[data-testid="conversation"]').forEach(conv => {
const name = conv.querySelector('[dir="ltr"] span')?.textContent || '';
const lastMsg = conv.querySelector('[data-testid="lastMessage"]')?.textContent || conv.querySelector('[dir="auto"]')?.textContent || '';
const time = conv.querySelector('time')?.getAttribute('datetime') || '';
const unread = !!conv.querySelector('[data-testid="unread"]');
const id = name + time;
if (!conversations.find(c => c.name === name && c.time === time)) {
conversations.push({ name, lastMessage: lastMsg.substring(0, 200), time, unread });
}
});
if (conversations.length === prevSize) retries++;
else retries = 0;
window.scrollTo(0, document.body.scrollHeight);
await sleep(CONFIG.scrollDelay);
}
const data = { exportedAt: new Date().toISOString(), count: conversations.length, conversations };
download(data, `xactions-conversations-${new Date().toISOString().slice(0, 10)}.json`);
console.log(`✅ Exported ${conversations.length} conversations`);
};
const run = async () => {
console.log('💬 DM MANAGER — XActions by nichxbt\n');
if (!window.location.href.includes('/messages')) {
console.error('❌ Navigate to x.com/messages first!');
return;
}
if (CONFIG.action === 'send') await sendDM();
else if (CONFIG.action === 'export') await exportConversations();
else console.error(`❌ Unknown action: ${CONFIG.action}`);
console.log('\n🏁 Done!');
};
run();
})();