// ==UserScript== // @name Post Action // @namespace https://github.com/RANSAA // @version 0.1.0 // @description 将当前页面的网址发送到指定的服务器,服务器地址信息需要再代码中修改以适合自己使用!目前已经支持视频地址获取站点:四色AV(335pai.com),黄色仓库(hsck.net,huangsecangku.net),e-hentai.org,exhentai.org // @author sayaDev // @license MIT License // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAAAXNSR0IArs4c6QAABXJJREFUWEfVmXtMW1Ucx7+nLS30AbRoJFsxY4hxk4CbZho02xKX6cLAIEPpDJoYn0HjI1NnjImPaCQzURNmcPqHiRlFGRHZljFlUcMkOt1whG3swUPo2P7YWmhLyy3ce8w5l0Jb+oBSRnr+aXrv+f3O5/xe59xzCBbRVhwc0SrdaVsoaDGAIoDkgdJsEOi5Wgo3CLkK0D4ApwlIp6j3to+UrvDEOyyJRzDH6iijQDVAKwAsVAcFSDMBvhu2GFsXOv6CBjNb7TsBsgug6xY6UPj+pAugn9ospob56psXcE6jvYBS7AHw8HwVL7BfGyF4Y7jK1BNLLiawudH+HCjq43B9rLFD31MQvGCrMu2LJhgV2Gy1fwLgrYWOvMj+tTaLaXckHRGBzVZ7HYCaRQ4er/hem8X0UjjhsMDLZNlQvrCWngM8HbNfxWuahMoRPB8a00HA09Wg+wYk2HznRQlBYWD1CAI2W+1HlrB0zRcytF+bzWLa5n84AywvCtgfr9YllnvCv7gEADtOJW4FSzQ+6bJZjOuZVg4s7w3oT4keJpH6CMgjbO/Bgc1WRxNAdyRygMTrIgdsFmMlYVtEhTvVHa4y6FQExbeoUGRSoev6FI6NTCaeI0TjhptVMKQQ/HNtCmM+GviWSvoJPYkUDk/la/DBei0UAXXEJwGNfQLeORn3djbmhC9VZkKjJNh1woPv+4Wg/iwsSLhVzaghOF2eyQO83yViwCVhtUGJXIOCK3jmuBtHbUtj7WjAAGoZ8Jzay9zS/KCBw33WM4EvznghUmBvsY67a3+fwIEz1ATWzQasMSp5X9u4hOrfXBh0S1ipVeD3knTu1p8vT6IyV40UBcGgW0R5uwt2gXLvfVmsw9aVaigJeNgVmlRIUSCshQG0EbPVcQGg+YG2Z8IXKo1QywaFRIGzoyK+vSigaUDg/1nrLM1Ajk7uxJ4xAK9IcceBUazSKzmwv7Fw8utrs03i2eNufHS3Fk/ma4Lk/f3DhQRALhJzg90JAtmcAW1jdgq+fkAHrSp4u3HVK2HjISfWGpVo2SKLVRxz8Ql1l2dy67x3yoNfr0zNAO/rncCH/3px5KF0FBiVPMw2HXaid0cmWGKfGxWx7agTrxWk4ZU7U7nOsMAULhYSUqS9A7N0Za4Gj+WqcVeW7CrWmgZ8uOQU8XZRGv9/fkzkv3kGJVQKoOU/Hw8lv4ULfxyFQ6DYs0GLqtUajHgk3Ns6hqEqI8+Td096uPf0KQTnKjIjAwM0LPDLa1OxM0+DK14Jj7a7uAIG0lGSAbNOwWP0h34BbxbKwJ6poPKDw8OTqDs7C5zT6OD9Pr5Hi+rbZoGHq4z8+at/jqN50MfjeOBxeRLhQ4IBhwmJ3UVpqFkju+bFP8ZxaNjHZ/93WQb/7XGIeLrDjRNlGbzPupYxXJuQONAkK339AgQRMxaOBOyvCK1DPtR0jqP0VjVPwhghMTfpbkpVcDhmVdYEkfLa6G/vd3nwzXmBu49NgFm43yXx+GS2LvvFBaePxgSuv1+Hkhw1V8viOtegnDkziJx0EbaUm7JTUFesQ6Z6FnRKAup7J1Db7ZUtm6VCw2Y9h/ZPjIXC52cmsEqvQMd22QOhFr7skXBf6xhPuINbDchPl8si8xIrfaxcvv7XOM+VkMbKWvQPTSZ8e4YS/U4R14XgWPUry9IQGDUKnojxNOZRrQoYcrP8j9pqIy7NsSSX4z1fmqNtfpYDKsqY8uaHdUiq7SVPimTbwE9bOXk+kWTgJPsInYZOns98ucDzY9XkOUjhVpaPV5PjqMpfA2OtfjeoPs/vMDAAOnmOW5fZ0vEdaM9AJ9OVgR86qS5lAhMsaa69QqtC0lwshoIvx9Xt/yOGmMNARdjRAAAAAElFTkSuQmCC // @match http://*/* // @match *://*/* // @require https://update.greasyfork.icu/scripts/494214/1432041/TKBaseSDK.js // @grant unsafeWindow // @grant GM_openInTab // @grant GM_xmlhttpRequest // @connect self // @connect localhost // @connect 127.0.0.1 // @connect * // @compatible chrome // @compatible edge // @compatible firefox // @compatible opera // @compatible safari // @noframes // @downloadURL none // ==/UserScript== /** * 目前支持的参数: * pageURL: 当前页面的url地址 * title: 当前网页的标题 * videoURL: pageURL页面中的视频地址,如果没有获取到视频地址则它的值与pageURL相同。 **/ // @downloadURL https://update.greasyfork.icu/scripts/556061/Post%20Action.user.js // @updateURL https://update.greasyfork.icu/scripts/556061/Post%20Action.meta.js /** * 配置信息,可更具需求更改配置 **/ const SERVER_CONFIG = { host: "127.0.0.1", //服务器地址 port: "80", //服务器端口,直接使用”“不指定端口 method: "POST", //请求方式 scheme: "http", //协议类型 taskAdd: "task/add", //yt-dlp 任务添加API Query Path路劲地址 }; /** * 站点类型,不同的站点类型对应的Button不同 **/ const WebType = { ytdlp: 0, exhentai: 1 }; //当前站点类型样式,默认为yt-dlp样式 let currentWebType = WebType.ytdlp /** * 将参数组装成JSON格式 * 获取当前需要的所有属性 * pageURL: 当前页面的url地址 * title: 当前网页的标题 * videoURL: pageURL页面中的视频地址,如果没有获取到视频地址则它的值与pageURL相同。 **/ function loadParameterJSON(){ // //示例 // var json = { // jsonrpc:'2.0', // method:'aria2.addUri', // id:url, // params:[ // [url], // ] // } // return JSON.stringify(json) //网页地址 let pageURL = window.location.href; //标题 let title = filterVideoTitle(); //视频链接 let videoURL = filterVideoLink(); let json = { "pageURL": pageURL, "title": title, "videoURL":videoURL }; return JSON.stringify(json) } (function() { 'use strict'; //默认为yt-dlp样式 currentWebType = WebType.ytdlp TKBaseSDK.initToast(); addSendServerButton(); })(); // -------------------------------复写TKBaseSDK.js中的方法------------------------------- /** * 创建一个自定义的Button并返回。 --> TKBaseSDK.createListItemButton()方法内部有一个SVG对象,该方法没有 * text: 显示的文字 * return:button **/ function createListItemButton(text){ // 创建一个包含按钮的DIV元素 let itemButton = document.createElement("TKButtonItem"); itemButton.setAttribute("class", "TKButtonListItemStyle"); // // 根据文字创建SVG // let itemSVG = createSVGElement(text); // itemSVG.setAttribute("class", "TKButtonListItemStyle"); // 将itemSVG添加到itemButton中 // itemButton.appendChild(itemSVG); return itemButton } // -------------------------------复写TKBaseSDK.js中的方法------------------------------- // -------------------------------Setup UI------------------------------- function addSendServerButton(){ //添加style TKBaseSDK.addButtonStyle(); //根据域名添加不同的按钮 let host = window.location.host let exhentai = [ "e-hentai.org", "exhentai.org", ] // if (exhentai.includes(host)) { currentWebType= WebType.exhentai setupExhentaiButton() }else{ currentWebType= WebType.ytdlp setupDefaultYtDlpButton() } } /** * 安装默认的yt-dlp按钮 **/ function setupDefaultYtDlpButton(){ //创建Send URL按钮 // let sendURL = TKBaseSDK.createListItemButton("Send URL"); let sendURL = createListItemButton(""); sendURL.appendChild(createIMGElement("Send URL")); //定义的是事件被触发后要做的事情 sendURL.addEventListener("click", function() { console.log("currentWebType:",currentWebType) sendLocationURLAction(); }); //创建Copy URL按钮 // let copyURL = TKBaseSDK.createListItemButton("Copy URL"); let copyURL = createListItemButton(""); copyURL.appendChild(createIMGElement("Copy URL")); //定义的是事件被触发后要做的事情 copyURL.addEventListener("click", function() { copyLocationURLAction(); }); //创建Copy M3u8按钮 // let copyM3u8 = TKBaseSDK.createListItemButton("Copy M3U8"); let copyM3u8 = createListItemButton(""); copyM3u8.appendChild(createIMGElement("Copy M3U8")); //定义的是事件被触发后要做的事情 copyM3u8.addEventListener("click", function() { copyM3u8LinkAction(); }); //创建Copy yt-dlp-n按钮 // let copyYtDlpN = TKBaseSDK.createListItemButton("Copy yt-dlp-n"); let copyYtDlpN = createListItemButton(""); copyYtDlpN.appendChild(createIMGElement("Copy yt-dlp-n")); //定义的是事件被触发后要做的事情 copyYtDlpN.addEventListener("click", function() { copy_yt_dlp_n_M3U8LinkAction(); }); //创建Copy yt-dlp按钮 // let copyYtDlp = TKBaseSDK.createListItemButton("Copy yt-dlp"); let copyYtDlp = createListItemButton(""); copyYtDlp.appendChild(createIMGElement("Copy yt-dlp")); //定义的是事件被触发后要做的事情 copyYtDlp.addEventListener("click", function() { copy_yt_dlp_M3U8LinkAction(); }); //创建Copy Magnet按钮 // let copyMagnet = TKBaseSDK.createListItemButton("Copy Magnet"); let copyMagnet = createListItemButton(""); copyMagnet.appendChild(createIMGElement("Copy Magnet")); copyMagnet.addEventListener("click", function() { copyMagnetLinksAction(); }); let list = document.createElement("TKButtonList"); list.className = "TKButtonListStyle"; list.appendChild(sendURL); //list.appendChild(copyURL); list.appendChild(copyM3u8); list.appendChild(copyYtDlpN); list.appendChild(copyYtDlp); //list.appendChild(copyMagnet); document.body.appendChild(list); } /** * 安装exhentai站点对应的按钮 **/ function setupExhentaiButton(){ //创建Send URL按钮 // let sendURL = TKBaseSDK.createListItemButton("Send URL"); let sendURL = createListItemButton(""); sendURL.appendChild(createIMGElement("Send URL")); //定义的是事件被触发后要做的事情 sendURL.addEventListener("click", function() { console.log("currentWebType:",currentWebType) sendLocationURLAction(); }); //创建Copy hentai按钮 // let copyHentai = TKBaseSDK.createListItemButton("Copy yt-dlp-n"); let copyHentai = createListItemButton(""); copyHentai.appendChild(createIMGElement("Copy hentai")); //定义的是事件被触发后要做的事情 copyHentai.addEventListener("click", function() { copy_hentai_Action(); }); //创建Copy hentai按钮 // let copyHentai = TKBaseSDK.createListItemButton("Copy yt-dlp-n"); let copyHentaiN = createListItemButton(""); copyHentaiN.appendChild(createIMGElement("Copy hentai-n")); //定义的是事件被触发后要做的事情 copyHentaiN.addEventListener("click", function() { copy_hentai_AtlasName_Action(); }); //创建Copy copyHentaiName按钮 // let copyHentaiName = TKBaseSDK.createListItemButton("Copy yt-dlp-n"); let copyHentaiName = createListItemButton(""); copyHentaiName.appendChild(createIMGElement("Copy Title")); //定义的是事件被触发后要做的事情 copyHentaiName.addEventListener("click", function() { copy_hentai_name_Action(); }); let list = document.createElement("TKButtonList"); list.className = "TKButtonListStyle"; // list.appendChild(sendURL); list.appendChild(copyHentaiN); // list.appendChild(copyHentai); // list.appendChild(copyHentaiName); document.body.appendChild(list); } // -------------------------------Setup UI------------------------------- // -------------------------------Action------------------------------- /** * 发送数据当前页面的URL到指定服务器 */ function sendLocationURLAction() { console.log(`Send Server`); //服务器的地址 var serverUrl = SERVER_CONFIG.scheme + "://" + SERVER_CONFIG.host + ":" + SERVER_CONFIG.port + "/" + SERVER_CONFIG.taskAdd; if (SERVER_CONFIG.port === "" ) { serverUrl = SERVER_CONFIG.scheme + "://" + SERVER_CONFIG.host + "/" + SERVER_CONFIG.taskAdd; } //发送的参数数据 let data = loadParameterJSON(); console.log(`serverUrl: ${serverUrl}`); console.log(`parameter: ${data}`); //GM_xmlhttpRequest方式请求 GM_xmlhttpRequest({ method: SERVER_CONFIG.method, url: serverUrl, headers: { 'Content-Type': 'application/json; charset=utf-8', }, data: data, onload: function(response) { console.log(response); console.log(`readyState:${response.readyState}`); console.log(`status:${response.status}`); console.log(`statusText:${response.statusText}`); console.log(`responseHeaders:\n${response.responseHeaders}`); console.log(`responseText:${response.responseText}`); if (response.status === 200) { console.log(`Send URL Success: ${url}`); TKBaseSDK.showToast("当前URL地址发送成功!",1); } else { console.log(`Send URL Error: ${url} statusText: ${response.statusText}`); TKBaseSDK.showToast("当前URL地址发送失败!",0); } }, onerror: function(response) { // 请求发生错误时执行 console.error("Request failed:", response); let msg = `发送失败,Send Server服务地址:${response.finalUrl}`; console.log(msg); TKBaseSDK.showToastWtihTime(msg, 0, 4000); } }); } /** * 拷贝当前网页地址 **/ function copyLocationURLAction(){ //当前网页地址 let url = window.location.href; TKBaseSDK.copyToClipBoard(url); TKBaseSDK.showToast("复制成功!",1); } /** * 获取并拷贝m3u8链接 **/ function copyM3u8LinkAction(){ let m3u8URL = filterVideoLink(); if (m3u8URL === "" || m3u8URL === window.location.href) { TKBaseSDK.showToast("复制失败,没有找到M3U8链接!",0); TKBaseSDK.copyToClipBoard(""); }else{ TKBaseSDK.showToast("复制成功!",1); //拷贝到剪切板 TKBaseSDK.copyToClipBoard(m3u8URL); } } /** * 拷贝四色AV中的标题与m3u8链接,并且组装yt-dlp-n命令 * 格式: yt-dlp-n "视频标题" "m3u8视频地址" **/ function copy_yt_dlp_n_M3U8LinkAction(){ let videoURL = filterVideoLink(); let title = filterVideoTitle(); if (videoURL === "" || title === "") { TKBaseSDK.showToast("yt-dlp-n下载命令复制失败,没有找到视频链接!",0); TKBaseSDK.copyToClipBoard(""); }else{ TKBaseSDK.showToast("yt-dlp-n下载命令复制成功!",1); //拷贝到剪切板 let cmd = "yt-dlp " + "\"" + title + "\"" + " \"" + videoURL + "\"" + ""; TKBaseSDK.copyToClipBoard(cmd); } } /** * 拷贝当前网页链接, 并组装yt-dlp命令 * 格式:yt-dlp "网页地址" **/ function copy_yt_dlp_M3U8LinkAction(){ let videoURL = filterVideoLink(); TKBaseSDK.showToast("yt-dlp下载命令复制成功!",1); //拷贝到剪切板 let cmd = "yt-dlp " + "\"" + videoURL + "\"" + ""; TKBaseSDK.copyToClipBoard(cmd); } /** * 功能:拷贝当前页面的所有magnet磁力链接 **/ function copyMagnetLinksAction(){ const magnetLinks = getMagnetLinks(); // 转换成换行分隔的字符串 const magnetLinksString = magnetLinks.join('\n'); if (magnetLinksString === "" ) { TKBaseSDK.showToast("Copy Mangnet失败,没有找到磁力链接!",0); TKBaseSDK.copyToClipBoard(""); }else{ TKBaseSDK.showToast("Copy Mangnet成功!",1); //拷贝到剪切板 TKBaseSDK.copyToClipBoard(magnetLinksString); } } /** * 功能:拷贝e-hentai.org,exhentai.org站点的hentai下载链接 与 当前图集的名称 **/ function copy_hentai_AtlasName_Action(){ //当前网页地址 let url = window.location.href; console.log("url:",url) //当前页面图集的标题 let title = window.document.title; // 移除末尾的 "- E-Hentai Galleries" title = title.replace(/\s*-\s*E-Hentai Galleries$/i, '').trim(); // 处理文件名中的特殊字符 title = sanitizeFileName(title); console.log("title:",title) //当前图集图片数量 let picCount = hentai_getAlbumPicCount() console.log("picCount:",picCount) //拷贝到剪切板 let cmd = "hentai -u " + "\"" + url + "\"" + " -n " + "\"" + title + "\"" + " -s "+ "-r "; if (picCount != null){ cmd = "hentai -u " + "\"" + url + "\"" + " -n " + "\"" + title + "\"" + " -t " + picCount + " -s "+ "-r "; } TKBaseSDK.copyToClipBoard(cmd); TKBaseSDK.showToast("hentai-n下载命令复制成功!",1); } /** * 功能:拷贝e-hentai.org,exhentai.org站点的hentai下载链接 **/ function copy_hentai_Action(){ //当前网页地址 let url = window.location.href; TKBaseSDK.showToast("hentai下载命令复制成功!",1); //拷贝到剪切板 let cmd = "hentai -u " + "\"" + url + "\"" + " -s "+ "-r "; TKBaseSDK.copyToClipBoard(cmd); } /** * 获取e-hentai.org,exhentai.org站点当前图集的名称 **/ function copy_hentai_name_Action(){ let title = window.document.title; // 移除末尾的 "- E-Hentai Galleries" title = title.replace(/\s*-\s*E-Hentai Galleries$/i, '').trim(); // 处理文件名中的特殊字符 title = sanitizeFileName(title); TKBaseSDK.copyToClipBoard(title); // TKBaseSDK.showToast("当前图集名称复制成功!",1); // let msg = "图集名称[" + title + "]复制成功!" let msg = "图集名称:" + title TKBaseSDK.showToast(msg,1); } // -------------------------------Action------------------------------- // -------------------------------解析视频地址和标题------------------------------- /** * 过滤获取当前视频指定的名称 **/ function filterVideoTitle(){ // 默认使用网站标题作为title var title = document.title; //匹配四色AV站点标题 let fourColorAVTitle = getFourColorAVTitle(); if (fourColorAVTitle) { title = fourColorAVTitle; } //匹配黄色仓库 let hsckTitle = getHuangSeCangKuTitle(); if (hsckTitle) { title = hsckTitle; } //匹配其它站点... //去掉字符串两端的空格和不可见字符(例如空格、换行、制表符等) title = title.trim(); // 处理文件名中的特殊字符 title = sanitizeFileName(title); return title } /** * 过滤并获取视频地址,如果没有获取到视频地址则直接使用window.location.href **/ function filterVideoLink(){ // 默认使用当前页面地址 var videoURL = window.location.href; //获取四色AV的视频地址 let fourColorAVURL = getFourColorAVM3u8Url(); if (fourColorAVURL) { // 等效 fourColorAVURL !== "" videoURL = fourColorAVURL; } // 黄色仓库 let hsckVideoURL = getHuangSeCangKuM3U8Url(); if (hsckVideoURL) { videoURL = hsckVideoURL; } //其它站点... return videoURL } /** * 获取四色AV中的m3u8链接地址 **/ function getFourColorAVM3u8Url(){ // // Define a regular expression to match the playUrl variable pattern // const playUrlPattern = /var playUrl\s*=\s*"([^"]+)"/; // // Get all script tags on the page // const scripts = Array.from(document.getElementsByTagName('script')); // // Look for the script containing the playUrl variable // const matchedScript = scripts.find(script => playUrlPattern.test(script.textContent)); // var m3u8Url = "" // // If found, extract the URL // if (matchedScript) { // const match = matchedScript.textContent.match(playUrlPattern); // m3u8Url = match && match[1]; // //将域名占位符转换正真正的主机 - 已弃用:不能写死 // m3u8Url = m3u8Url.replace(/\+\@movivecom\@\+/g, "qfvgzy.com"); // console.log('四色AV站点:m3u8 URL:', m3u8Url); // } else { // console.warn('四色AV站点:m3u8 URL could not be found.'); // } var m3u8Url = "" // 获取地址的新方法 // 判断变量playUrl是否存在, 直接获取playUrl变量的值。 if (typeof playUrl !== "undefined") { m3u8Url = playUrl; } m3u8Url = m3u8Url.trim(); console.log('四色AV站点:m3u8 URL:', m3u8Url); return m3u8Url } /** * 获取四色AV中视频的标题 **/ function getFourColorAVTitle(){ var title = "" // 获取包含 h1 元素的 div.main 元素 const mainDiv = document.querySelector('.wrap > .main'); // 确认 main 元素存在 if (mainDiv) { // 在 mainDiv 内查找 h1 元素 const h1Element = mainDiv.querySelector('h1'); // 确认 h1 元素存在 if (h1Element) { // 获取 h1 元素的文本内容 const h1Content = h1Element.textContent.trim(); console.log('四色AV站点:查找h1 内容为:', h1Content); title = h1Content } else { console.warn('四色AV站点:查找视频标题时未找到 h1 元素!'); } } else { console.warn('四色AV站点:查找视频标题时未找到 .main 元素!'); } return title } /** * 获取黄色仓库的视频地址 * 站点1:huangsecangku.net * 站点2:hsck.net * 站点3:hsck.app **/ function getHuangSeCangKuM3U8Url(){ var m3u8Url = ""; // 判断变量player_aaaa.url是否存在,并且直接根据player_aaaa.url的值来获取视频地址 if (typeof player_aaaa !== "undefined" && player_aaaa.url !== undefined) { m3u8Url = player_aaaa.url; } m3u8Url = m3u8Url.trim(); console.log('黄色仓库站点:m3u8 URL:', m3u8Url); return m3u8Url; } /** * 获取黄色仓库标题 **/ function getHuangSeCangKuTitle(){ var title = "" /** * trim():去掉字符串两端的空格和不可见字符(例如空格、换行、制表符等) * if (text) 自动判断 null, undefined, "" **/ const quearyTitle = document.querySelector(".stui-warp-content h3.title")?.textContent?.trim(); if (quearyTitle) {//查询到的表示有效 title = quearyTitle; } console.log('黄色仓库站点:Video Title:', title); return title } /** * 获取页面中的所有magnet磁力链接 **/ function getMagnetLinks(){ // 从整个 HTML 文档中提取磁力链接 const htmlContent = document.documentElement.innerHTML; const magnetRegex = /magnet:\?xt=urn:[a-zA-Z0-9:]+/g; const magnetLinks = Array.from(new Set(htmlContent.match(magnetRegex) || [])); console.log(magnetLinks); return magnetLinks; } // -------------------------------解析视频地址和标题------------------------------- // -------------------------------hentai e-xhentai.org 站点资源解析------------------------------- /** * 获取当前图集图片数量 **/ function hentai_getAlbumPicCount(){ const cells = document.querySelectorAll('td.gdt2'); for (let cell of cells) { const text = cell.textContent.trim(); if (/pages|页/i.test(text)) { const match = text.match(/\d+/); if (match) return parseInt(match[0], 10); } } return null; } // -------------------------------hentai e-xhentai.org 站点资源解析------------------------------- // -------------------------------处理文件名合规性------------------------------- /** * 功能:将字符串中不能作为文件名的字符替换成"_",并且如果存在英文的双引号"替换成英文的单引号' * replace(/"/g, '“'); //正则表达式 * replaceAll('"', '“'); //直接替换函数 **/ function sanitizeFileName(filename) { //使用正则表达式将"替换成' var name = filename; //去掉字符串两端的空格和不可见字符(例如空格、换行、制表符等) name = name.trim(); name = name.replace(/"/g, "'"); //注意:这儿使用的正则表达式无法将"替换成',然后再调用这个函数的外部直接对字符串操作又可以,不知道是什么原因。所以直接使用replaceAll方法进行替换。 name = name.replaceAll('"', "'"); name = name.replaceAll(':', ":"); name = name.replaceAll('”', "'"); name = name.replaceAll('!', "!"); // name = name.replaceAll('/', "|"); name = name.replaceAll('/', "⁄"); //将不能作为文件名的字符替换为:_ name = name.replace(/[:]+/g, '_'); // -osx // name = name.replace(/[\/\\:*?"<>|]+/g, '_'); // win return name } /** * 功能:将字符串中不能作为路径的字符替换成”_“ **/ function sanitizePath(path) { return path.replace(/[\/\\:*?"<>|]+/g, '_'); // 替换为单个下划线 } // -------------------------------处理文件名合规性------------------------------- // -------------------------------文字生成图片------------------------------- /** * 功能:将文字生成PNG图片 * text: 文字内容 * width: 图片宽度 * height: 图片高度 * 使用示例: const img = document.createElement("img"); img.src = textToImage("Copy yt-dlp-n",128,44); document.body.appendChild(img); **/ function textToImage(text, width, height) { const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; const ctx = canvas.getContext("2d"); // 设置背景填充颜色,需要执行fillRect,fill等方法才会生效 ctx.fillStyle = "#1ca7ee"; // // 填充背景为矩形 // ctx.fillRect(0, 0, 44, 44); // // 填充背景为圆形 // // 获取圆形半径(取宽高中的最小值的一半) // const radius = Math.min(width, height) / 2; // const centerX = width / 2; // const centerY = height / 2; // ctx.beginPath(); // ctx.arc(centerX, centerY, radius, 0, Math.PI * 2); // ctx.fill(); // 绘制文字 ctx.fillStyle = "#fff"; ctx.font = "700 14px Arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; // ✅文字绘制在画布中心 ctx.fillText(text, canvas.width / 2, canvas.height / 2); return canvas.toDataURL("image/png"); } /** * 功能:创建128x44的IMG对象 * text:图片显示的内容 **/ function createIMGElement(text) { let imgItem = document.createElement("img"); imgItem.src = textToImage(text,128,44); return imgItem; } // -------------------------------文字生成图片-------------------------------