Greasy Fork is available in English.
Add a picture download button to Twitter, and click to download the original image named by format.
当前为
// ==UserScript==
// @name TwitterImg Downloader
// @namespace TypeNANA
// @version 0.1
// @description Add a picture download button to Twitter, and click to download the original image named by format.
// @author HY
// @match https://twitter.com/
// @include https://twitter.com/*
// @require http://code.jquery.com/jquery-3.3.1.min.js
// @grant none
// ==/UserScript==
(function () {
/** 修改 defaultFileName 可改变默认文件名格式
*
* <%Userid> 画师的推特ID,如 “shiratamacaron”
* <%Name> 【慎用】画师的推特名,如 “しらたま”,可能会有无法作为文件名的字符出现
* <%Tid> 图片源的推文id,如 “1095705491429158912”
* <%Time> 保存时间,13位时间戳,如 “1550557810891”
* <%PicName> 图片的默认文件名,如 “DzS6RkJUUAA_0LX”
*
* 建议<%Time>和<%PicName>至少使用一个来作为图片区分
* 默认格式为 “<%Userid> <%Tid> <%PicName>” ,效果为 “shiratamacaron 1095705491429158912 DzS6RkJUUAA_0LX”
*/
let defaultFileName = "<%Userid> <%Tid> <%PicName>";
function download(url, name, view) {
name = name || url
fetch(url).then(response => {
if (response.status == 200)
return response.blob();
throw new Error(`status: ${response.status}.`)
}).then(blob => {
downloadFile(name, blob, view)
}).catch(error => {
console.log("failed. cause:", error)
})
}
function downloadFile(fileName, blob, view) {
const anchor = view;
const src = URL.createObjectURL(blob);
anchor.download = fileName;
anchor.href = src;
view.click();
}
const addDownloadButton = () => {
let tweets = document.querySelectorAll('.tweet');
tweets.forEach((t) => {
let dl_userid = t.getAttribute("data-screen-name");
let dl_name = t.getAttribute("data-name");
let dl_tid = t.getAttribute("data-tweet-id");
//尝试获取发推时间,但是部分情况无法获取,故采用保存文件时间
//let dl_time = t.getElementsByClassName("_timestamp")[0].getAttribute("data-time");
let dl_time = new Date().getTime();
let actionList = t.querySelector('.ProfileTweet-actionList');
if (actionList) {
let Images = t.querySelectorAll('.AdaptiveMedia-container img');
Images.forEach((Img) => {
if (Img) {
let ImgUrl = Img.src + ":orig";
if (Img.src.includes('blob')) return;
if (Img.parentElement.parentElement.getElementsByClassName("dl_btn_div").length != 0) return;
let dlbtn = document.createElement('div');
Img.parentElement.parentElement.appendChild(dlbtn);
dlbtn.outerHTML = '<div class="dl_btn_div" style="display: table;font-size: 15px;color: white;position: absolute;right: 5px;bottom: 5px;background: #0000007f;height: 30px;width: 30px;border-radius: 15px;text-align: center;"><a style="display: table-cell;height: 30px;width: 30px;vertical-align: middle;color:white;font-family:edgeicons;text-decoration: none;user-select: none;" id="a_dl"></a></div>';
dlbtn = Img.parentElement.parentElement.getElementsByClassName("dl_btn_div")[0];
let btnDownloadImg = document.createElement('A');
btnDownloadImg.className = 'img-link';
actionList.appendChild(btnDownloadImg);
let dl_picname = Img.src.replace('https://pbs.twimg.com/media/', '').replace('.png', '').replace('.jpg', '');
let dl_filename = defaultFileName
.replace("<%Userid>", dl_userid)
.replace("<%Name>", dl_name)
.replace("<%Tid>", dl_tid)
.replace("<%Time>", dl_time)
.replace("<%PicName>", dl_picname);
dlbtn.addEventListener('click', function () {
download(ImgUrl, dl_filename, btnDownloadImg);
});
}
});
}
});
}
window.onload = function () {
addDownloadButton();
}
waitForKeyElements(
'.AdaptiveMedia-container img',
addDownloadButton
);
function waitForKeyElements(
selectorTxt,
actionFunction,
bWaitOnce,
iframeSelector
) {
var targetNodes, btargetsFound;
if (typeof iframeSelector == "undefined"){
targetNodes = $(selectorTxt);
} else {
targetNodes = $(iframeSelector).contents().find(selectorTxt);
}
if (targetNodes && targetNodes.length > 0) {
btargetsFound = true;
targetNodes.each(function () {
var jThis = $(this);
var alreadyFound = jThis.data('alreadyFound') || false;
if (!alreadyFound) {
var cancelFound = actionFunction(jThis);
if (cancelFound){
btargetsFound = false;
} else {
jThis.data('alreadyFound', true);
}
}
});
} else {
btargetsFound = false;
}
var controlObj = waitForKeyElements.controlObj || {};
var controlKey = selectorTxt.replace(/[^\w]/g, "_");
var timeControl = controlObj[controlKey];
if (btargetsFound && bWaitOnce && timeControl) {
clearInterval(timeControl);
delete controlObj[controlKey]
} else {
if (!timeControl) {
timeControl = setInterval(function () {
waitForKeyElements(selectorTxt,
actionFunction,
bWaitOnce,
iframeSelector
);
},
300
);
controlObj[controlKey] = timeControl;
}
}
waitForKeyElements.controlObj = controlObj;
}
})();