// ==UserScript==
// @name pikpak番号重命名助手
// @name:zh-CN pikpak番号重命名助手
// @namespace Cheerchen37_NameScope
// @version 0.5
// @description 自动从AVwiki网站获取信息并填充到mypikpak.com网站上的重命名对话框中,以帮助用户快速重命名文件。脚本在mypikpak.com的对话框触发时自动执行,从而提高用户在管理带番号的文件时的效率和准确性。
// @author [email protected]
// @match *://*mypikpak.com/*
// @grant GM_xmlhttpRequest
// @grant GM_openInTab
// @license MIT
// ==/UserScript==
(function() {
'use strict';
console.log("脚本已加载");
// 1. 定位到元素的部分
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(node => {
if (node.className === "el-dialog") {
handleDialog(node);
}
});
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
function handleDialog(node) {
const input = node.querySelector('input.el-input__inner[type="text"]');
if (!input) return;
const cid = input.value;
const keyword = extractKeyword(cid);
if (!keyword) {
console.log("未能提取有效关键字");
return;
}
queryAVwiki(keyword, input);
}
// 2. 提取查询元素的部分
function extractKeyword(text) {
// 尝试匹配包含字母和数字的模式,忽略后面的字符
let match = text.match(/([a-zA-Z]+)-(\d+)/);
if (match) {
// if (match[2].length == 4){
// return `${match[1]}0${match[2]}`;
// }
// return `${match[1]}00${match[2]}`;
return match[0];
}
// 如果上面的特殊格式未匹配,尝试更通用的匹配
match = text.match(/([a-zA-Z]+)0(\d+)/);
if (match) {
return match[0];
}
match = text.match(/([a-zA-Z]{3,})(\d+)/);
return match ? `${match[1]}-${match[2]}` : null;
}
function extractKeywordDMM(text) {
// 尝试匹配包含字母和数字的模式,忽略后面的字符
let match = text.match(/([a-zA-Z]+)-(\d+)/);
if (match) {
if (match[2].length == 4){
return `${match[1]}0${match[2]}`;
}
return `${match[1]}00${match[2]}`;
}
// 如果上面的特殊格式未匹配,尝试更通用的匹配
match = text.match(/([a-zA-Z]+)0(\d+)/);
if (match) {
return match[0];
}
match = text.match(/([a-zA-Z]{3,})(\d+)/);
return match ? match[0] : null;
}
// 4. 使用关键字查询DMM的部分
function queryDMM(keyword, input) {
console.log("keyword " + keyword);
const encodedKeyword = encodeURIComponent(keyword);
const url = `https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=${encodedKeyword}/?i3_ref=search&i3_ord=1`;
console.log("url " + url);
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function(response) {
if (response.responseText.includes('404 Not Found')) {
fallbackSearch(encodedKeyword, input);
} else {
parseResponseDMM(response.responseText, input);
}
},
onerror: function(error) {
console.log("请求出错: ", error);
}
});
}
// 4. 使用关键字查询DMM的部分
function queryAVwiki(keyword, input) {
console.log("keyword " + keyword);
const encodedKeyword = encodeURIComponent(keyword);
const url = `https://av-wiki.net/?s=${encodedKeyword}&post_type=product`;
console.log("url " + url);
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function(response) {
const parser = new DOMParser();
const doc = parser.parseFromString(response.responseText, "text/html");
const listItems = doc.querySelectorAll('.post .archive-list .read-more a');
const keywordRegex = new RegExp(keyword.match(/[a-zA-Z]+/)[0], 'i');
// 查找第一个有效链接
for (let item of listItems) {
if (item.href) {
if (!keywordRegex.test(item.href)){
continue;
}
const detailUrl = item.href;
console.log("detailUrl "+ detailUrl)
GM_xmlhttpRequest({
method: "GET",
url: detailUrl,
onload: function(response) {
parseResponseWiki(response.responseText, input);
}
});
return; // 找到有效链接后结束循环
}
}
// 如果没有找到有效链接,设置输入框显示未找到
input.value = '未找到有效链接';
},
onerror: function(error) {
console.log("请求出错: ", error);
input.value = "请求错误,请检查网络";
}
});
}
// Fallback search on failure
function fallbackSearch(keyword, input) {
const searchUrl = `https://www.dmm.co.jp/search/=/searchstr=${encodeURIComponent(keyword)}/limit=30/sort=rankprofile/`;
console.log("fallbackSearch "+ searchUrl)
GM_xmlhttpRequest({
method: "GET",
url: searchUrl,
onload: function(response) {
const parser = new DOMParser();
const doc = parser.parseFromString(response.responseText, "text/html");
const listItems = doc.querySelectorAll('#list li .tmb a');
// 提取输入中的连续字母部分
const keywordRegex = new RegExp(keyword.match(/[a-zA-Z]+/)[0], 'i');
const digiRegex = new RegExp("digital", 'i');
const monoRegex = new RegExp("mono", 'i');
// 查找第一个有效链接
for (let item of listItems) {
if (item.href) {
if (!keywordRegex.test(item.href)){
continue;
}
if (!digiRegex.test(item.href) && !monoRegex.test(item.href)){
continue;
}
const detailUrl = item.href;
console.log("detailUrl "+ detailUrl)
GM_xmlhttpRequest({
method: "GET",
url: detailUrl,
onload: function(response) {
parseResponseDMM(response.responseText, input);
}
});
return; // 找到有效链接后结束循环
}
}
// 如果没有找到有效链接,设置输入框显示未找到
input.value = '未找到有效链接';
},
onerror: function(error) {
console.log("请求出错: ", error);
input.value = "请求错误,请检查网络";
}
});
}
// Parse response and update input
function parseResponseDMM(html, input) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
// 尝试从meta标签中提取备选信息
const ogTitle = doc.querySelector('#title');
const ogUrl = doc.querySelector('meta[property="og:url"]');
let name = ogTitle ? ogTitle.textContent : '未找到产品名称';
let sku = '未找到产品SKU';
if (ogUrl && ogUrl.content) {
const match = ogUrl.content.match(/cid=([^\/]+)/);
if (match) {
sku = match[1].toLowerCase();
}
}
const script = doc.querySelector('script[type="application/ld+json"]');
if (script) {
try {
const data = JSON.parse(script.textContent);
name = data.name || name;
sku = data.sku.toLowerCase() || sku;
} catch (error) {
console.error("解析JSON-LD数据时出错: ", error);
}
}
// 清理名称中的特殊字符
name = name.replace(/[\/:*?"<>|\x00-\x1F]/g, '_');
input.value = `${sku} ${name} `;
triggerInputChange(input)
}
function parseResponseWiki(html, input) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
// 尝试从meta标签中提取备选信息
const ogTitle = doc.querySelector('.blockquote-like p');
let name = ogTitle ? ogTitle.textContent : '未找到产品名称';
// 清理名称中的特殊字符
name = name.replace(/[\/:*?"<>|\x00-\x1F]/g, '_');
input.value = `${name} `;
triggerInputChange(input)
}
function triggerInputChange(element) {
// 创建一个新的键盘事件
var event = new Event('input', {
bubbles: true,
cancelable: true,
});
element.value = element.value.trim(); // 移除空格
element.dispatchEvent(event); // 再次触发input事件
}
})();