您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
将 Pixiv/Twitter/Booru 图片页面中的信息以 JSON 或字符串形式导出。
当前为
// ==UserScript== // @name Image Webinfo // @name:zh-CN 图片网页信息提取 // @version 1.3.1 // @description Extract JSON-/string-style info from Pixiv/Twitter/Booru image pages. // @description:zh-CN 将 Pixiv/Twitter/Booru 图片页面中的信息以 JSON 或字符串形式导出。 // @author wklchris // @match https://danbooru.donmai.us/posts/* // @match https://www.pixiv.net/artworks/* // @match https://x.com/*/status/* // @grant none // @license MIT // @namespace https://greasyfork.org/users/672201 // ==/UserScript== (function() { 'use strict'; // --- Customization --- // Specify returned keys when copy string let pixiv_str_keys = [ // 'artist', // 'illust_id', 'artist_id', 'post_date', 'post_title' ]; let booru_str_keys = [ // 'artists', // 'copyrights', // 'characters', // 'general', 'booru_id', 'rating_level' ]; // --- Main --- let artwork_data = {}; let export_json_btn = document.createElement("button"); export_json_btn.innerHTML = "Export WebInfo as JSON"; let export_str_btn = document.createElement("button"); export_str_btn.innerHTML = "Export WebInfo as String"; // General functions function logMessage(msg) { console.log("[ImageWebInfo] " + msg); } let popMessage = 'Image webinfo exported to clipboard.'; function copyToClipboard(s) { try { navigator.clipboard.writeText(s); } catch (err) { popMessage = 'Image webinfo export failed.'; logMessage(popMessage); } } function attemptedQuerySelector(qs, callback) { // querySelector may not find the element when the website loads slowly. // Keep attempting until found or exceed the given maximum attempts. var attempts = 0, max_attempts = 20; var attemptCall = function() { var elem = document.querySelector(qs); if (elem) { console.log(`Found querySelector '${qs}' in ${attempts} attempts`); return callback(elem); } else { attempts++; if (attempts >= max_attempts) { console.warn(`Could not find: ${qs} within ${max_attempts} attempts`); } else { setTimeout(attemptCall, 4000*(attempts + 1)/max_attempts + 1000) } } }; attemptCall(); } // --- Pixiv posts --- if (location.hostname.includes("pixiv")) { function getPixivInfo(as_JSON=true) { let data = {}; // Get user let user_tag = document.querySelector('aside div[aria-haspopup="true"] > div > a'); data['artist'] = user_tag.childNodes[0].innerText let split_user_url = user_tag.href.split('/'); data['artist_id'] = split_user_url[split_user_url.length - 1]; // Get post id let split_url = location.href.split('/'); data['illust_id'] = split_url[split_url.length - 1]; // Get upload date let timestr = document.getElementsByTagName('time')[0].innerText; let time_seps = {'year': '年', 'month': '月', 'day': '日'}; let i_start = 0, i_end = -1, tmp_data = {}; for (const [key, sep] of Object.entries(time_seps)) { i_start = i_end+1; i_end = timestr.search(sep); tmp_data[key] = timestr.substring(i_start, i_end); } data['post_date'] = `${tmp_data['year']}-${tmp_data['month'].padStart(2, 0)}-${tmp_data['day'].padStart(2, 0)}`; // Get post title (if having a title) let title_dom = document.querySelector('figcaption h1'); data['post_title'] = title_dom ? title_dom.innerText : '' ; let s = ""; if (as_JSON == true) { s = JSON.stringify(data) } else { s = pixiv_str_keys.map((x, i) => data[x]).join("\t"); } copyToClipboard(s); return data; } // Add buttons & their click functions let search_booru_btn = document.createElement("button"); search_booru_btn.innerHTML = "Search artist on Booru"; let search_booru_illust_btn = document.createElement("button"); search_booru_illust_btn.innerHTML = "Search illust on Booru"; attemptedQuerySelector('aside section button', (exist_dom) => { exist_dom.parentNode.insertBefore(export_json_btn, exist_dom.nextSibling); exist_dom.parentNode.insertBefore(export_str_btn, export_json_btn.nextSibling); exist_dom.parentNode.insertBefore(search_booru_btn, export_str_btn.nextSibling); exist_dom.parentNode.insertBefore(search_booru_illust_btn, search_booru_btn.nextSibling); }); export_json_btn.onclick = function() { artwork_data = getPixivInfo(true); export_json_btn.style.background = 'lightgreen'; export_str_btn.style.removeProperty("background"); }; export_str_btn.onclick = function() { artwork_data = getPixivInfo(false); export_str_btn.style.background = 'lightgreen'; export_json_btn.style.removeProperty("background"); }; search_booru_btn.onclick = function() { if (!('artist_id' in artwork_data)) { artwork_data = getPixivInfo(false); } let _prefix = "https://danbooru.donmai.us/artists?commit=Search&search%5Border%5D=created_at&search%5Burl_matches%5D=https%3A%2F%2Fwww.pixiv.net%2Fusers%2F"; let _url = _prefix + artwork_data["artist_id"]; window.open(_url, "_blank"); }; search_booru_illust_btn.onclick = function() { if (!('illust_id' in artwork_data)) { artwork_data = getPixivInfo(false); } let illust_search_prefix = "https://danbooru.donmai.us/posts?tags=pixiv%3A"; let illust_search_url = illust_search_prefix + artwork_data["illust_id"]; window.open(illust_search_url, "_blank"); }; } // --- Twitter/X Post --- if (["twitter.com", "x.com"].includes(location.hostname)) { let twitter_url_id = ''; function getTwitterInfo(as_JSON=true) { let data = {}; // Get user let user_tag = document.querySelector('article > div div[data-testid="User-Name"]'); data['artist'] = user_tag.childNodes[0].innerText; // -- Twitter user only has username, doesn't have a user ID number. // The matched id is only used for creating search buttons. data['artist_id'] = ''; let split_user_url = user_tag.childNodes[1].querySelector('a').href.split('/'); twitter_url_id = split_user_url[split_user_url.length - 1]; // Get post id data['illust_id'] = "T" + location.href.split('status/')[1].split('/')[0]; // Get upload date data['post_date'] = document.getElementsByTagName('time')[0].dateTime.split('T')[0]; // Get post title (if having a title) let tweet_nodes = document.querySelector('article div[data-testid="tweetText"]').querySelectorAll('span, img'); data['post_title'] = Array.from(tweet_nodes).map( elem => elem.alt || elem.innerText.trim()).filter(d => d.length && d[0] != '#' ).join('').split('\n')[0]; let s = ""; if (as_JSON == true) { s = JSON.stringify(data) } else { s = pixiv_str_keys.map((x, i) => data[x]).join("\t"); } copyToClipboard(s); return data; } // Add buttons & their click functions let search_booru_btn = document.createElement("button"); search_booru_btn.innerHTML = "Search artist on Booru"; let search_booru_illust_btn = document.createElement("button"); search_booru_illust_btn.innerHTML = "Search illust on Booru"; attemptedQuerySelector('div[data-testid="User-Name"]', (exist_dom) => { exist_dom.parentNode.insertBefore(export_json_btn, exist_dom.nextSibling); exist_dom.parentNode.insertBefore(export_str_btn, export_json_btn.nextSibling); exist_dom.parentNode.insertBefore(search_booru_btn, export_str_btn.nextSibling); exist_dom.parentNode.insertBefore(search_booru_illust_btn, search_booru_btn.nextSibling); }); export_json_btn.onclick = function() { artwork_data = getTwitterInfo(true); export_json_btn.style.background = 'lightgreen'; export_str_btn.style.removeProperty("background"); }; export_str_btn.onclick = function() { artwork_data = getTwitterInfo(false); export_str_btn.style.background = 'lightgreen'; export_json_btn.style.removeProperty("background"); }; search_booru_btn.onclick = function() { if (!('artist_id' in artwork_data)) { artwork_data = getTwitterInfo(false); } let _prefix = "https://danbooru.donmai.us/artists?commit=Search&search%5Border%5D=created_at&search%5Burl_matches%5D=https%3A%2F%2Fwww.twitter.com%2F"; let _url = _prefix + twitter_url_id; window.open(_url, "_blank"); }; search_booru_illust_btn.onclick = function() { if (!('illust_id' in artwork_data)) { artwork_data = getTwitterInfo(false); } let illust_search_prefix = "https://danbooru.donmai.us/posts?tags=source%3A"; let illust_search_url = illust_search_prefix + encodeURIComponent(location.href.replace('x.com/','twitter.com/')); window.open(illust_search_url, "_blank"); }; } // --- Booru posts --- if (location.hostname.includes("booru")) { // Add renamed link let renamed_download_link = document.createElement("a"); renamed_download_link.href = document.getElementById('post-option-download').querySelector('a').href; renamed_download_link.style.display = 'inline-block'; renamed_download_link.style.paddingBottom = '3px'; renamed_download_link.text = "RENAMED FILENAME"; // Add listener so that the renamed text is copied when right-click renamed_download_link.addEventListener('contextmenu', function(event) { let _renamed_filename = renamed_download_link.innerText; navigator.clipboard.writeText(_renamed_filename) }); function getBooruInfo(as_JSON=true) { let data = {}; let tag_list = document.getElementById("tag-list").querySelector("div"); function query_tags(ul_class, sep=", ") { // Get tag list by ul_class name. Join by sep if multiple. let query_str = `ul.${ul_class} a.search-tag`; let _tags = tag_list.querySelectorAll(query_str); return Array.from(_tags).map((x, i) => x.innerText).join(sep) } data["artists"] = query_tags("artist-tag-list"); data["copyrights"] = query_tags("copyright-tag-list"); data["characters"] = query_tags("character-tag-list"); data["general"] = query_tags("general-tag-list"); // Get information (rating-levels, etc.) function query_by_id(dom_id, remove_str) { let _text = document.getElementById(dom_id).innerText; return _text.replace(remove_str, "").trim(); } data["booru_id"] = query_by_id("post-info-id", "ID:"); data["rating_level"] = query_by_id("post-info-rating", "Rating:"); let s = ""; if (as_JSON == true) { s = JSON.stringify(data) } else { s = booru_str_keys.map((x, i) => data[x]).join("\t"); } copyToClipboard(s); return data; } function updateRenamedDownloadLink() { let renamed_filename = ''; const file_link = document.getElementById('post-info-size').querySelector('a').href; const post_sources = document.getElementById('post-info-source').querySelectorAll('a'); const post_url = post_sources[0].href; const post_imgurl = post_sources[post_sources.length - 1].href; function getSitePostId() { const _site_url = post_sources[0].href; const _site_id = _site_url.substring(_site_url.lastIndexOf('/') + 1); return _site_id; } function getSiteFilenamePrefix(site_url) { const prefix_dict = { 'pixiv.net': '', 'fanbox.cc': 'PF', 'patreon.com': 'PT', 'twitter.com': 'T', 'x.com': 'T' }; for (const key in prefix_dict) { if (site_url.includes(key)) { return prefix_dict[key]; } } return '#'; } if (post_url.includes('pixiv.net') ) { // If pixiv, simply return original filename (from last <a> in sources) renamed_filename = post_imgurl.substring(post_imgurl.lastIndexOf('/') + 1); } else { // Otherwise, find the parent/children relations of the current post const children_previews = document.querySelector('.posts-container'); let id_child = 0; // If not found parent if (children_previews) { const articles = children_previews.querySelectorAll('article'); for (let i = 0; i < articles.length; i++) { if (articles[i].classList.contains('current-post')) { id_child = i; break; }; } } // Concat the filename const file_prefix = getSiteFilenamePrefix(post_url); const site_id = getSitePostId(); const file_ext = file_link.substring(file_link.lastIndexOf('.')); renamed_filename = file_prefix + site_id + "_p" + id_child + file_ext; } // Update the renamed link element renamed_download_link.download = renamed_filename; renamed_download_link.text = renamed_filename; } // Update link for (renamed) image file download updateRenamedDownloadLink(); // Add renamed link and buttons attemptedQuerySelector('section[id="search-box"]', (exist_dom) => { exist_dom.parentNode.insertBefore(renamed_download_link, exist_dom.nextSibling); exist_dom.parentNode.insertBefore(export_json_btn, renamed_download_link.nextSibling); exist_dom.parentNode.insertBefore(export_str_btn, export_json_btn.nextSibling); }); export_json_btn.onclick = function() { artwork_data = getBooruInfo(true); export_json_btn.style.background = 'lightgreen'; export_str_btn.style.removeProperty("background"); }; export_str_btn.onclick = function() { artwork_data = getBooruInfo(false); export_str_btn.style.background = 'lightgreen'; export_json_btn.style.removeProperty("background"); }; } })();