-
-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy patharticlePublisher.js
More file actions
144 lines (127 loc) · 4.98 KB
/
Copy patharticlePublisher.js
File metadata and controls
144 lines (127 loc) · 4.98 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
142
143
144
// Copyright (c) 2024-2026 nich (@nichxbt). Licensed under the Apache License, Version 2.0.
// scripts/articlePublisher.js
// Browser console script for publishing long-form articles on X (Premium+ required)
// Paste in DevTools console on x.com/compose/article
// by nichxbt
(() => {
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
// =============================================
// CONFIGURATION
// =============================================
const CONFIG = {
title: 'My Article',
body: 'Article content goes here. Replace this with your full article text.',
action: 'draft', // 'draft' | 'publish'
dryRun: true, // SET FALSE TO EXECUTE
};
// =============================================
const SELECTORS = {
title: '[data-testid="articleTitle"], h1[contenteditable]',
body: '[data-testid="articleBody"], [data-testid="richTextEditor"]',
publish: '[data-testid="articlePublish"]',
saveDraft: '[data-testid="articleSaveDraft"]',
};
const typeInto = async (el, text) => {
el.focus();
// Use execCommand for contenteditable elements
if (el.contentEditable === 'true') {
document.execCommand('selectAll', false, null);
document.execCommand('insertText', false, text);
} else {
// For regular inputs
const nativeSet = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set
|| Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set;
if (nativeSet) {
nativeSet.call(el, text);
el.dispatchEvent(new Event('input', { bubbles: true }));
} else {
el.value = text;
el.dispatchEvent(new Event('input', { bubbles: true }));
}
}
await sleep(300);
};
const run = async () => {
console.log('📝 Article Publisher — Long-form Content');
console.log('━'.repeat(50));
console.log(` Title: "${CONFIG.title}"`);
console.log(` Body: ${CONFIG.body.length} chars`);
console.log(` Action: ${CONFIG.action}`);
console.log(` Dry run: ${CONFIG.dryRun}`);
console.log('');
// Check we're on the right page
if (!window.location.href.includes('/compose/article')) {
console.log('⚠️ Navigate to x.com/compose/article first (Premium+ required).');
console.log('🔗 Redirecting...');
window.location.href = 'https://x.com/compose/article';
return;
}
await sleep(2000);
// Find title input
const titleEl = document.querySelector(SELECTORS.title);
if (!titleEl) {
console.error('❌ Title field not found. Premium+ may be required, or the page hasn\'t loaded.');
console.log(' Tried selectors:', SELECTORS.title);
return;
}
// Find body editor
const bodyEl = document.querySelector(SELECTORS.body);
if (!bodyEl) {
console.error('❌ Body editor not found.');
console.log(' Tried selectors:', SELECTORS.body);
return;
}
console.log('✅ Found title and body fields.');
if (CONFIG.dryRun) {
console.log('\n🔒 DRY RUN — no changes made.');
console.log(' Would fill title:', CONFIG.title);
console.log(' Would fill body:', CONFIG.body.slice(0, 100) + (CONFIG.body.length > 100 ? '...' : ''));
console.log(` Would ${CONFIG.action === 'publish' ? 'PUBLISH' : 'SAVE DRAFT'}`);
console.log('\n💡 Set CONFIG.dryRun = false to execute.');
return;
}
// Fill title
console.log('📝 Filling title...');
await typeInto(titleEl, CONFIG.title);
console.log('✅ Title entered.');
// Fill body
console.log('📝 Filling body...');
await typeInto(bodyEl, CONFIG.body);
console.log('✅ Body entered.');
await sleep(1000);
// Perform action
if (CONFIG.action === 'publish') {
const publishBtn = document.querySelector(SELECTORS.publish);
if (!publishBtn) {
console.error('❌ Publish button not found. Saving as draft instead.');
const draftBtn = document.querySelector(SELECTORS.saveDraft);
if (draftBtn) {
draftBtn.click();
console.log('💾 Saved as draft (publish button unavailable).');
}
return;
}
console.log('🚀 Publishing article...');
publishBtn.click();
await sleep(3000);
console.log('✅ Article published!');
} else {
const draftBtn = document.querySelector(SELECTORS.saveDraft);
if (!draftBtn) {
console.error('❌ Save Draft button not found.');
console.log(' Tried selector:', SELECTORS.saveDraft);
return;
}
console.log('💾 Saving draft...');
draftBtn.click();
await sleep(2000);
console.log('✅ Draft saved!');
}
console.log('\n📊 Summary:');
console.log(` Title: ${CONFIG.title}`);
console.log(` Length: ${CONFIG.body.length} characters`);
console.log(` Action: ${CONFIG.action === 'publish' ? 'Published' : 'Saved as draft'}`);
console.log(` Time: ${new Date().toLocaleString()}`);
};
run();
})();