AI-powered LinkedIn Content Generator

Generate engaging LinkedIn posts with AI assistance

Size

11.9 KB

Version

1.0.1

Created

Oct 25, 2025

Updated

20 days ago

1// ==UserScript==
2// @name		AI-powered LinkedIn Content Generator
3// @description		Generate engaging LinkedIn posts with AI assistance
4// @version		1.0.1
5// @match		https://*.linkedin.com/*
6// @icon		https://static.licdn.com/aero-v1/sc/h/akt4ae504epesldzj74dzred8
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('AI-powered LinkedIn Content Generator initialized');
12
13    // Add custom styles for the AI button and modal
14    TM_addStyle(`
15        .ai-generate-btn {
16            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17            color: white;
18            border: none;
19            padding: 8px 16px;
20            border-radius: 16px;
21            font-size: 14px;
22            font-weight: 600;
23            cursor: pointer;
24            margin: 8px;
25            display: inline-flex;
26            align-items: center;
27            gap: 6px;
28            transition: all 0.3s ease;
29            box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
30        }
31        
32        .ai-generate-btn:hover {
33            transform: translateY(-2px);
34            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
35        }
36        
37        .ai-generate-btn:disabled {
38            opacity: 0.6;
39            cursor: not-allowed;
40            transform: none;
41        }
42        
43        .ai-modal-overlay {
44            position: fixed;
45            top: 0;
46            left: 0;
47            right: 0;
48            bottom: 0;
49            background: rgba(0, 0, 0, 0.6);
50            display: flex;
51            align-items: center;
52            justify-content: center;
53            z-index: 9999;
54            backdrop-filter: blur(4px);
55        }
56        
57        .ai-modal {
58            background: white;
59            border-radius: 12px;
60            padding: 24px;
61            max-width: 500px;
62            width: 90%;
63            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
64        }
65        
66        .ai-modal h2 {
67            margin: 0 0 16px 0;
68            color: #333;
69            font-size: 20px;
70        }
71        
72        .ai-modal textarea {
73            width: 100%;
74            min-height: 100px;
75            padding: 12px;
76            border: 2px solid #e0e0e0;
77            border-radius: 8px;
78            font-size: 14px;
79            font-family: inherit;
80            resize: vertical;
81            margin-bottom: 16px;
82            box-sizing: border-box;
83        }
84        
85        .ai-modal textarea:focus {
86            outline: none;
87            border-color: #667eea;
88        }
89        
90        .ai-modal-buttons {
91            display: flex;
92            gap: 12px;
93            justify-content: flex-end;
94        }
95        
96        .ai-modal-btn {
97            padding: 10px 20px;
98            border-radius: 8px;
99            font-size: 14px;
100            font-weight: 600;
101            cursor: pointer;
102            border: none;
103            transition: all 0.2s ease;
104        }
105        
106        .ai-modal-btn-primary {
107            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
108            color: white;
109        }
110        
111        .ai-modal-btn-primary:hover {
112            transform: translateY(-1px);
113            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
114        }
115        
116        .ai-modal-btn-primary:disabled {
117            opacity: 0.6;
118            cursor: not-allowed;
119            transform: none;
120        }
121        
122        .ai-modal-btn-secondary {
123            background: #f0f0f0;
124            color: #333;
125        }
126        
127        .ai-modal-btn-secondary:hover {
128            background: #e0e0e0;
129        }
130        
131        .ai-loading {
132            display: inline-block;
133            width: 14px;
134            height: 14px;
135            border: 2px solid rgba(255, 255, 255, 0.3);
136            border-top-color: white;
137            border-radius: 50%;
138            animation: spin 0.8s linear infinite;
139        }
140        
141        @keyframes spin {
142            to { transform: rotate(360deg); }
143        }
144    `);
145
146    // Debounce function to avoid multiple rapid calls
147    function debounce(func, wait) {
148        let timeout;
149        return function executedFunction(...args) {
150            const later = () => {
151                clearTimeout(timeout);
152                func(...args);
153            };
154            clearTimeout(timeout);
155            timeout = setTimeout(later, wait);
156        };
157    }
158
159    // Function to create and show the AI prompt modal
160    function showAIPromptModal(targetEditor) {
161        const overlay = document.createElement('div');
162        overlay.className = 'ai-modal-overlay';
163        
164        const modal = document.createElement('div');
165        modal.className = 'ai-modal';
166        
167        modal.innerHTML = `
168            <h2>✨ AI Content Generator</h2>
169            <textarea id="ai-prompt-input" placeholder="Describe what you want to post about... 
170
171Examples:
172• Write a post about the importance of work-life balance
173• Share insights on AI in software development
174• Announce a new job position
175• Celebrate a team achievement"></textarea>
176            <div class="ai-modal-buttons">
177                <button class="ai-modal-btn ai-modal-btn-secondary" id="ai-cancel-btn">Cancel</button>
178                <button class="ai-modal-btn ai-modal-btn-primary" id="ai-generate-btn">Generate Post</button>
179            </div>
180        `;
181        
182        overlay.appendChild(modal);
183        document.body.appendChild(overlay);
184        
185        const promptInput = modal.querySelector('#ai-prompt-input');
186        const cancelBtn = modal.querySelector('#ai-cancel-btn');
187        const generateBtn = modal.querySelector('#ai-generate-btn');
188        
189        // Focus on input
190        promptInput.focus();
191        
192        // Close modal on overlay click
193        overlay.addEventListener('click', (e) => {
194            if (e.target === overlay) {
195                overlay.remove();
196            }
197        });
198        
199        // Cancel button
200        cancelBtn.addEventListener('click', () => {
201            overlay.remove();
202        });
203        
204        // Generate button
205        generateBtn.addEventListener('click', async () => {
206            const prompt = promptInput.value.trim();
207            
208            if (!prompt) {
209                alert('Please enter a description for your post');
210                return;
211            }
212            
213            // Disable button and show loading
214            generateBtn.disabled = true;
215            generateBtn.innerHTML = '<span class="ai-loading"></span> Generating...';
216            
217            try {
218                console.log('Generating LinkedIn post with AI...');
219                
220                // Call AI to generate the post
221                const aiPrompt = `Create an engaging LinkedIn post based on this topic: "${prompt}"
222
223Requirements:
224- Professional yet conversational tone
225- 150-250 words
226- Include relevant emojis (but not too many)
227- Add 3-5 relevant hashtags at the end
228- Make it engaging and authentic
229- Use line breaks for readability
230
231Generate only the post content, nothing else.`;
232
233                const generatedPost = await RM.aiCall(aiPrompt);
234                
235                console.log('AI post generated successfully');
236                
237                // Insert the generated content into the LinkedIn editor
238                insertContentIntoEditor(targetEditor, generatedPost);
239                
240                // Close modal
241                overlay.remove();
242                
243            } catch (error) {
244                console.error('Error generating post:', error);
245                alert('Failed to generate post. Please try again.');
246                generateBtn.disabled = false;
247                generateBtn.textContent = 'Generate Post';
248            }
249        });
250        
251        // Allow Enter key to submit (with Shift+Enter for new line)
252        promptInput.addEventListener('keydown', (e) => {
253            if (e.key === 'Enter' && !e.shiftKey) {
254                e.preventDefault();
255                generateBtn.click();
256            }
257        });
258    }
259
260    // Function to insert content into LinkedIn's editor
261    function insertContentIntoEditor(editor, content) {
262        try {
263            // Try to find the contenteditable div
264            const editableDiv = editor.querySelector('[contenteditable="true"]') || 
265                               editor.querySelector('.ql-editor') ||
266                               editor;
267            
268            if (editableDiv) {
269                // Set focus first
270                editableDiv.focus();
271                
272                // Clear existing content
273                editableDiv.innerHTML = '';
274                
275                // Insert new content with proper formatting
276                const lines = content.split('\n');
277                lines.forEach((line, index) => {
278                    if (line.trim()) {
279                        const p = document.createElement('p');
280                        p.textContent = line;
281                        editableDiv.appendChild(p);
282                    } else if (index < lines.length - 1) {
283                        // Add empty paragraph for line breaks
284                        const br = document.createElement('p');
285                        br.innerHTML = '<br>';
286                        editableDiv.appendChild(br);
287                    }
288                });
289                
290                // Trigger input event to notify LinkedIn
291                editableDiv.dispatchEvent(new Event('input', { bubbles: true }));
292                editableDiv.dispatchEvent(new Event('change', { bubbles: true }));
293                
294                console.log('Content inserted successfully');
295            } else {
296                console.error('Could not find editable element');
297            }
298        } catch (error) {
299            console.error('Error inserting content:', error);
300        }
301    }
302
303    // Function to add AI button to the post editor
304    function addAIButtonToEditor(editorContainer) {
305        // Check if button already exists
306        if (editorContainer.querySelector('.ai-generate-btn')) {
307            return;
308        }
309        
310        // Find the toolbar or button container
311        const toolbar = editorContainer.querySelector('[class*="share-actions"]') ||
312                       editorContainer.querySelector('[class*="share-box-footer"]') ||
313                       editorContainer.querySelector('[class*="editor-content"]');
314        
315        if (toolbar) {
316            const aiButton = document.createElement('button');
317            aiButton.className = 'ai-generate-btn';
318            aiButton.innerHTML = '✨ Generate with AI';
319            aiButton.type = 'button';
320            
321            aiButton.addEventListener('click', (e) => {
322                e.preventDefault();
323                e.stopPropagation();
324                showAIPromptModal(editorContainer);
325            });
326            
327            // Insert button at the beginning of toolbar
328            toolbar.insertBefore(aiButton, toolbar.firstChild);
329            console.log('AI button added to editor');
330        }
331    }
332
333    // Observer to detect when post editor opens
334    const observePostEditor = debounce(() => {
335        // Look for the post creation modal/editor
336        const editors = document.querySelectorAll('[class*="share-creation-state"]');
337        
338        editors.forEach(editor => {
339            if (editor.offsetParent !== null) { // Check if visible
340                addAIButtonToEditor(editor);
341            }
342        });
343        
344        // Also check for the expanded editor modal
345        const modal = document.querySelector('[role="dialog"][class*="share"]');
346        if (modal) {
347            addAIButtonToEditor(modal);
348        }
349    }, 500);
350
351    // Set up mutation observer to watch for editor appearance
352    const observer = new MutationObserver(observePostEditor);
353    
354    // Start observing when body is ready
355    TM_runBody(() => {
356        observer.observe(document.body, {
357            childList: true,
358            subtree: true
359        });
360        
361        // Initial check
362        observePostEditor();
363        
364        console.log('Watching for LinkedIn post editor...');
365    });
366
367})();
AI-powered LinkedIn Content Generator | Robomonkey