// ==UserScript==
// @name zhihuPostCopy
// @namespace http://tampermonkey.net/
// @version 2024-08-04
// @description zhihu Post Copy
// @author You
// @match https://zhuanlan.zhihu.com/write
// @match https://zhuanlan.zhihu.com/p/*
// @match https://baijiahao.baidu.com/builder/rc/edit*
// @match https://creator.xiaohongshu.com/publish/publish
// @match https://cp.11467.com/home/personal/news_add.html
// @match https://cp.11467.com/home/personal/product_add.html
// @match https://member.bilibili.com/platform/upload/text/edit
// @match https://member.bilibili.com/article-text/home*
// @match https://mp.sohu.com/mpfe/v4/contentManagement/news/addarticle*
// @match http://mp.163.com/subscribe_v4/index.html#/article-publish
// @icon https://www.google.com/s2/favicons?sz=64&domain=zhihu.com
// @grant GM.setValue
// @grant GM.getValue
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// article-copy.tsx
var tips = function(msg) {
document.querySelectorAll(".article-tips-span").forEach((span2) => {
span2.remove();
});
const span = document.createElement("span");
span.textContent = msg;
span.className = "article-tips-span";
span.style.cssText = `position: fixed;width: fit-content;padding: 0.5em 1em;background: #000;box-shadow: 0 6px 12px -6px #222;border-radius: 6px;left: 0;right: 0;top: 20vh;margin: auto;color: #fff;z-index: 99;font-size: 13px;`;
setTimeout(() => {
span.remove();
}, 3000);
document.body.appendChild(span);
};
var fetchArticle = function() {
const url = /^https:\/\/zhuanlan.zhihu.com\/p\/\d+$/;
const { href } = window.location;
if (!url.test(href)) {
return;
}
const title = document.title.split(/\s+/).filter((s) => s.trim())[0] || "";
const h1 = document.querySelector("h1")?.innerText.trim();
const realy_title = title || h1 || "";
const container = document.querySelector(".Post-RichTextContainer .RichText");
const content = container?.innerHTML || "";
const data = { title: realy_title, content };
document.querySelectorAll(".article-copy").forEach((e) => {
e.remove();
});
const div = document.createElement("div");
div.className = "article-copy";
div.style.cssText = "position:fixed;top:3em;right:2em;border-radius:6px;z-index:999;background:#222;color:#fff;cursor:pointer;padding:0.5em 1em;box-shadow:0 6px 12px -6px #222;";
div.textContent = "\u590D\u5236\u6587\u7AE0";
div.addEventListener("click", () => {
globalThis.GM.setValue("ARTICLE_CACHE", JSON.stringify(data));
tips("\u590D\u5236\u5B8C\u6210");
});
document.body.appendChild(div);
};
var entry = function(data) {
const url = /^https:\/\/zhuanlan.zhihu.com\/p\/\d+$/;
const { href } = window.location;
if (url.test(href)) {
return;
}
if (!data) {
return;
}
class WebComponentExt extends HTMLElement {
constructor() {
super(...arguments);
}
html_content(html) {
const doc = new DOMParser().parseFromString(`<html><body>${html}</body></html>`, "text/html");
const text = doc.body.innerText;
return text;
}
html_images(html) {
const container = document.createElement("div");
container.innerHTML = html;
const images = [];
container.querySelectorAll("img").forEach((img) => {
const src = img.getAttribute("src");
const original = img.getAttribute("data-original");
if (original && original.startsWith("http")) {
images.push(original);
} else if (src && src.startsWith("http")) {
images.push(src);
}
});
return images;
}
copy_image(e) {
const src = e.getAttribute("src");
if (src) {
this.imgToBlob(src).then((blob) => {
navigator.clipboard.writeText(src);
const buff = new ClipboardItem({
"image/png": blob
});
navigator.clipboard.write([buff]).then(() => {
tips("\u590D\u5236\u6210\u529F");
});
});
}
}
copy(text, html) {
this.async_copy(text, html).then(() => {
tips("\u590D\u5236\u6210\u529F");
});
}
insert(item) {
this.insert_xiaohongshu(item);
this.insert_baijiahao(item);
}
insert_xiaohongshu(item) {
if (!/xiaohongshu\.com/.test(window.location.hostname)) {
return;
}
if (!window.location.pathname.endsWith("/publish/publish")) {
return;
}
const title = document.querySelector(".titleInput input");
if (!title) {
return;
}
this.setNativeValue(title, item.title);
this.fireInputEvent(title);
const content = document.querySelector("#post-textarea");
const text = this.html_content(item.content);
const html = text.replace(/\n{2}/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/\n/g, "<br>");
if (content) {
content.innerHTML = html;
this.fireInputEvent(content);
}
}
insert_baijiahao(item) {
if (!/baidu\.com/.test(window.location.hostname)) {
return;
}
if (!window.location.pathname.endsWith("/builder/rc/edit")) {
return;
}
const title = document.querySelector(".client_pages_edit_components_titleInput textarea");
if (!title) {
console.log("title input not found");
return;
}
this.setNativeValue(title, item.title);
this.fireInputEvent(title);
}
insert_bilibili(item) {
const url2 = "https://member.bilibili.com//article-text/home";
if (!window.location.href.startsWith(url2)) {
return;
}
const title = document.querySelector(".bre-title-input textarea");
if (!title) {
return;
}
this.setNativeValue(title, item.title);
this.fireInputEvent(title);
}
render_style() {
const style = document.createElement("style");
style.innerHTML = `
.hidden .item, .hidden .images{
display: none;
}
.item{
display: flex;
flex-direction: row;
font-size: 12px;
cursor:pointer;
}
.item span:first-child{
flex: 1;
}
.item .copy{
padding-left: 1em;
color:#2c2;
}
.item *{
pointer-events: none;
}
.images{
align-items: center;
padding-top: 6px;
}
.images span{
padding-top: 100%;
position: relative;
background: #fff2;
border-radius: 3px;
}
.images img{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
transition: 0.3s all;
cursor:pointer;
width: 100%;
}
.images img:hover{
background: #fff2;
}
`;
return style;
}
render_images_html(images) {
const container = document.createElement("div");
container.className = "images";
let columns = "";
if (images.length === 1) {
columns = "1fr";
} else if (images.length === 2) {
columns = "1fr 1fr";
} else if (images.length === 3) {
columns = "1fr 1fr 1fr";
} else {
columns = "1fr 1fr 1fr 1fr";
}
container.style.cssText = `display:grid;grid-template-columns:${columns};grid-gap:4px;`;
images.forEach((url2) => {
const span = document.createElement("span");
span.innerHTML = `<img src="${url2}" crossOrigin="anonymous">`;
container.appendChild(span);
});
return container.outerHTML;
}
async imgToBlob(imgUrl) {
const img = new Image;
img.crossOrigin = "Anonymous";
return new Promise((resolve, reject) => {
img.onload = () => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx?.drawImage(img, 0, 0);
canvas.toBlob((blob) => {
if (blob) {
resolve(blob);
} else {
reject("\u56FE\u7247\u8F6C\u6362\u5931\u8D25");
}
}, "image/png");
};
img.onerror = function() {
reject("\u56FE\u7247\u52A0\u8F7D\u5931\u8D25");
};
img.src = imgUrl;
});
}
async async_copy(text, html) {
if (html) {
const doc = new DOMParser().parseFromString(`<html><body>${text}</body></html>`, "text/html");
const html2 = doc.documentElement.outerHTML;
const plain = doc.body.innerText;
const buff2 = new ClipboardItem({
"text/plain": new Blob([plain], { type: "text/plain" }),
"text/html": new Blob([html2], { type: "text/html" })
});
await navigator.clipboard.write([buff2]);
return;
}
const buff = new ClipboardItem({
"text/plain": new Blob([text], { type: "text/plain" })
});
await navigator.clipboard.write([buff]);
}
async load() {
const text = await globalThis.GM.getValue("ARTICLE_CACHE", "");
try {
const data2 = JSON.parse(text);
return Promise.resolve(data2);
} catch (error) {
return Promise.reject(error);
}
}
async render(data2) {
const { title, content } = data2;
const images = this.html_images(content);
const image_html = this.render_images_html(images);
const intro = this.html_content(content).substring(0, 10);
const container = document.createElement("div");
container.style.cssText = "position:fixed;top:2em;right:2em;z-index:999;padding:0.5em 1em;border-radius:6px;background:#000;color:#fff";
container.innerHTML = `<div class="item title"><span>\u6807\u9898\uFF1A${title}</span><span class="copy">\u590D\u5236</span></div><div class="item content"><span>\u6B63\u6587\uFF1A${intro}</span><span class="copy">\u590D\u5236</span></div>${image_html}`;
container.className = "root";
container.addEventListener("click", (e) => {
const target = e.target;
if (target.classList.contains("root")) {
if (target.classList.contains("hidden")) {
target.classList.remove("hidden");
} else {
target.classList.add("hidden");
}
return;
}
if (target.tagName === "IMG") {
this.copy_image(target);
return;
}
if (target.classList.contains("item")) {
if (target.classList.contains("title")) {
this.copy(title);
this.insert(data2);
} else if (target.classList.contains("content")) {
this.copy(content, true);
}
}
});
container.appendChild(this.render_style());
const shadow = this.attachShadow({ mode: "open" });
shadow.appendChild(container);
}
setNativeValue(element2, value) {
const { set: valueSetter } = Object.getOwnPropertyDescriptor(element2, "value") || {};
const prototype = Object.getPrototypeOf(element2);
const { set: prototypeValueSetter } = Object.getOwnPropertyDescriptor(prototype, "value") || {};
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element2, value);
} else {
if (valueSetter) {
valueSetter.call(element2, value);
} else {
throw new Error("The given element does not have a value setter");
}
}
}
fireInputEvent(element2) {
element2.dispatchEvent(new InputEvent("input", {
bubbles: true,
cancelable: false,
composed: true
}));
}
fireChangeEvent(element2) {
element2.dispatchEvent(new Event("change", {
bubbles: true,
cancelable: false
}));
}
fireClickEvent(element2) {
element2.dispatchEvent(new MouseEvent("click", {
bubbles: true,
cancelable: true,
button: 0,
composed: true
}));
}
connectedCallback() {
this.load().then((data2) => {
this.render(data2);
});
}
disconnectedCallback() {
}
}
const elements = document.querySelectorAll(".web-component-article,web-component-article");
if (elements.length > 0) {
elements.forEach((element2) => {
element2.remove();
});
}
const nodeName = `web-component-article-${Date.now()}`;
customElements.define(nodeName, WebComponentExt);
const element = document.createElement(nodeName);
element.className = "web-component-article";
if (window.top !== window) {
setTimeout(() => {
console.log("insert after 10s");
document.body.appendChild(element);
}, 1e4);
} else {
document.body.appendChild(element);
}
};
window.addEventListener("load", () => {
fetchArticle();
entry("highlight");
});
// Your code here...
})();