您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows navigating through tweets in tweetdeck by keyboard shorcuts. Also makes ctrl c copy the link of the currently loaded tweet.
// ==UserScript== // @name Tweetdeck gallery // @namespace https://github.com/argit2/tweetdeck-gallery // @version 1.0 // @description Allows navigating through tweets in tweetdeck by keyboard shorcuts. Also makes ctrl c copy the link of the currently loaded tweet. // @author You // @match https://tweetdeck.twitter.com/ // @grant GM_setClipboard // ==/UserScript== /* Usage Click somewhere in the page, type the number of the column you wanna see, and use letters j and k to navigate between media tweets Ctrl c when a tweet is open copies the link */ var firstTweet = true; var currentColumn = 1; var currentTweet = null; var nextTweet = null; // used as a safeguard in some scenarios where the currentTweet is lost const preemptiveLoad = 3; // if only this amount of tweets remaining to see, will attempt to load more function removeAllChildren (elem) { while (elem.lastElementChild) { elem.removeChild(elem.lastElementChild); } } function doOnceLoaded(selector, func) { let interv = setInterval(function() { if (document.querySelector(selector)) { func(); clearInterval(interv); } }, 500); // check every 100ms } function playVideo() { let vid = document.querySelector("video") if (vid) { vid.play(); } } function setAutoplay() { let node = document.querySelector("div#open-modal"); new MutationObserver(playVideo).observe(node, { childList: true}); } function gatherTweets() { return Array.filter(Array.from(document.querySelectorAll(`.js-column:nth-child(${currentColumn}) .js-column-holder article`)), elemExists); } function gatherMediaTweets() { let elements = gatherTweets(); let mediaTweets = Array.filter(elements, elem => { let linkElem = mediaLinkElem(elem); if (linkElem) { let link = linkElem.href; if (link.includes("t.co")) { return true; } } return false; }); return mediaTweets; } function loadNextTweets() { let elements = gatherTweets(); if (elements) { // goes up then down elements[elements.length - 2].scrollIntoView(false); elements[elements.length - 1].scrollIntoView(false); } } // doesn't really serve for anything lmfao function loadPrevTweets() { let elements = gatherTweets(); if (elements) { // goes down then up elements[1].scrollIntoView(false); elements[0].scrollIntoView(false); } } function elemExists(elem) { return elem && elem.style.visibility != "hidden" && elem.style.display !== "none"; } function getCurrentTweet () { if (! currentTweet) { resetCurrentTweet(); } return currentTweet; } function getRealCurrentTweet() { // gathers the one in the page instead of the clone } function setCurrentTweet (mediaTweets, tweet) { if (!tweet) { currentTweet = null; nextTweet = null; return; } currentTweet = tweet; let index = findIndexMediaTweet(mediaTweets, tweet); let next = getMediaTweet(mediaTweets, index + 1) if (next) { nextTweet = next; } else { nextTweet = null; } } function getMediaTweet(mediaTweets, index) { if (index < 0 || index >= mediaTweets.length) { return null; } return mediaTweets[index]; } function resetCurrentTweet () { let mediaTweets = gatherMediaTweets(); if (mediaTweets) { setCurrentTweet(mediaTweets, mediaTweets[0]); firstTweet = true; } else { print("Error: no mediaTweets on current column"); } } function mediaLinkElem (tweet) { let elem = tweet.querySelector("a.media-item"); if (!elem) { elem = tweet.querySelector("a.media-image"); } return elem; } function showCurrentTweet () { let current = getCurrentTweet(); let linkElem = mediaLinkElem(current); if (linkElem) { //linkElem.scrollIntoView(false); linkElem.click(); } } function findIndexMediaTweet(arr, tweet) { return arr.findIndex(x => { let elem1 = mediaLinkElem(x); let elem2 = mediaLinkElem(tweet); return elem1 && elem2 && elem1.href == elem2.href; }); } function currentTweetLost(mediaTweets, current){ console.log("Error: currentTweet lost. This is probably due to it being unloaded as the script scrolls down without being able to find media posts. Resetting value to first visible media post."); console.log("Lost tweet:", current); console.log("Visible media tweets:", mediaTweets); setCurrentTweet(mediaTweets, mediaTweets[0]); showCurrentTweet(); } function showNextTweet () { let current = getCurrentTweet(); let mediaTweets = gatherMediaTweets(); let index = 0; let indexToShow = 0; if (! firstTweet) { index = findIndexMediaTweet(mediaTweets, current); indexToShow = index + 1; } if (index == -1) { if (! nextTweet) { currentTweetLost(mediaTweets, current); return; } console.log(currentTweet, nextTweet); setCurrentTweet(mediaTweets, nextTweet); showCurrentTweet(); } else if (indexToShow < mediaTweets.length) { setCurrentTweet(mediaTweets, mediaTweets[indexToShow]); showCurrentTweet(); } // atempts to load more even if it's not the last if (indexToShow >= mediaTweets.length - preemptiveLoad) { loadNextTweets(); } firstTweet = false; } function showPreviousTweet () { let current = getCurrentTweet(); let mediaTweets = gatherMediaTweets(); let index = findIndexMediaTweet(mediaTweets, current); if (index == -1) { currentTweetLost(mediaTweets, current); return; } if (index >= 1) { setCurrentTweet(mediaTweets, mediaTweets[index - 1]); showCurrentTweet(); } if (index - 1 <= preemptiveLoad) { loadPrevTweets(); } firstTweet = false; } function setCurrentColumn (colNumber) { currentColumn = colNumber; resetCurrentTweet(); } function doc_keyUp(e) { let x = e.keyCode; if (x >= 49 && x <= 57){ // numbers setCurrentColumn(x - 48); } if (x == ctrlKey) { ctrlDown = false; } switch (x) { case cKey: if (ctrlDown) { copyOpenTweetLink(); } break; case jKey: showNextTweet(); break; case kKey: showPreviousTweet(); break; default: break; } } function doc_keyDown (e) { if (e.keyCode == ctrlKey) { ctrlDown = true; } } function copyOpenTweetLink() { let elem = document.querySelector("div#open-modal .tweet-timestamp a"); if (elem && elem.href) { GM_setClipboard(elem.href); } } const ctrlKey = 17, cKey = 67, jKey = 74, kKey = 75; var ctrlDown = false; doOnceLoaded("div#open-modal", setAutoplay); document.addEventListener('keyup', doc_keyUp, false); document.addEventListener('keydown', doc_keyDown, false);