// ==UserScript==
// @name Twitter Copy Button
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Adds a button to copy tweet content and link to clipboard when tweets come into view.
// @author RadicalRasmalai
// @match https://*.x.com/*
// @grant GM_setClipboard
// ==/UserScript==
(function() {
'use strict';
// Function to add the copy button to each tweet
function addCopyButton(tweet) {
// Check if the copy button is already added
if (tweet.querySelector('.copy-button')) return;
// Create the copy button
const button = document.createElement('button');
button.innerText = 'Copy';
button.className = 'copy-button';
button.style.position = 'absolute';
button.style.top = '0px';
button.style.right = '50px';
button.style.padding = '5px 10px';
button.style.backgroundColor = '#1DA1F2';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.style.zIndex = '1000'; // Ensure the button appears on top
// On click, copy the tweet content and link
button.addEventListener('click', function() {
const tweetTextElement = tweet.querySelector('[data-testid="tweetText"]');
const tweetText = tweetTextElement ? tweetTextElement.innerText : 'Tweet content not found';
const userNameElement = tweet.querySelector('[data-testid="User-Name"]');
const userName = userNameElement ? userNameElement.innerText : 'Username not found';
// Extract tweet link
const tweetLinkElement = tweet.querySelector('a[href*="/status/"]');
const tweetLink = tweetLinkElement ? tweetLinkElement.href : 'Link not found';
// Format the content to copy
const contentToCopy = `${userName}\nTweet: ${tweetText}\n\nLink: ${tweetLink}`;
GM_setClipboard(contentToCopy);
alert('Tweet content and link copied to clipboard!');
});
// Position the button in the bottom-right of the tweet
tweet.style.position = 'relative'; // Ensure the tweet has a positioning context
tweet.appendChild(button);
}
// Intersection Observer to detect when posts come into view
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
addCopyButton(entry.target); // Add button to the tweet
entry.target.setAttribute('data-counted', 'true'); // Mark this post as counted
observer.unobserve(entry.target); // Stop observing this post
}
});
}, {
threshold: 0.5
});
// Function to observe new posts
function observePosts() {
const posts = document.querySelectorAll('article:not([data-counted])'); // Select posts that have not been counted
posts.forEach(post => {
observer.observe(post);
});
}
// Initial observation
observePosts();
// Observe mutations in the document to handle dynamically loaded content
const mutationObserver = new MutationObserver(observePosts);
mutationObserver.observe(document, { childList: true, subtree: true });
// ==UserScript== // @name Twitter Copy Button // @namespace http://tampermonkey.net/ // @version 1.2 // @description Adds a button to copy tweet content and link to clipboard when tweets come into view. // @author RadicalRasmalai // @match https://*.x.com/* // @grant GM_setClipboard // ==/UserScript==
(function() { 'use strict';
})();