您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
bgm自动加条目和关联的基础库
此脚本不应直接安装,它是供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/407699/845520/bgm_wikihelpercorejs.js
async function baseGet(url,type,ua) { if (!type) { type = 'document' }; if (ua) { ua= "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36''Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36"; }else{ ua=undefined; } return new Promise((resolve,reject) => { GM_xmlhttpRequest({ method: 'get', url: url, headers: { 'User-Agent': ua, 'Referer': url }, responseType: type, onload: function(res){ if(res.status==200){ // console.log(res) return resolve(res) }else if(res.status.toString().startsWith('50')){ reject(res); } else{ // console.log('ret') resolve(); return false; } } }) }) } async function get(url,type,ua){ return baseGet(url,type,ua).catch(function(err){ // console.log(err) if(err){ return get(url,type,ua) } }) } /**/ async function basePost(url, data, fd) { let ctType if (fd) { ctType = undefined } else { ctType = "application/x-www-form-urlencoded" } return new Promise((resolve,reject) => { GM_xmlhttpRequest({ method: 'post', url: url, data: data, headers: { "Content-Type": ctType, 'Referer': url }, onload: function(res){ if(res.status==200){ // console.log(res) return resolve(res) }else{ // console.log('ret') reject(res); } } }) }) } async function post(url, data, fd){ return basePost(url, data, fd).catch(function(err){ // console.log(err) if(err){ return post(url, data, fd) } }) } //获取url的html内容 async function getResBody(url,ua) { let res = await get(url,undefined,ua); let body; if(res){ body = res.responseText; return body }else{ console.error(`链接${url}返回40x,无法正常访问`) } // console.log(res) // if(res.status!==200){ // return getResBody(url) // }else{ // body = res.responseText; // return $(body); // } } //过滤特殊字符串 function stripscript(s) { let pattern = new RegExp("[`~★☆○·!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“’。,、?]") let rs = ""; for (var i = 0; i < s.length; i++) { rs = rs + s.substr(i, 1).replace(pattern, ' '); } return rs; } //将rgb()改成hex值 function convertRGBDecimalToHex(rgb) { var regex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/; var values = regex.exec(rgb); if (values.length != 4) { return rgb; // fall back to what was given. } var r = Math.round(parseFloat(values[1])); var g = Math.round(parseFloat(values[2])); var b = Math.round(parseFloat(values[3])); return "#" + (r + 0x10000).toString(16).substring(3).toUpperCase() + (g + 0x10000).toString(16).substring(3).toUpperCase() + (b + 0x10000).toString(16).substring(3).toUpperCase(); } //formhash不是一成不变的,所以加上了时间戳判定,每24小时更新一次 async function getFormhash() { let localFormhash = localStorage.bgm_wikihelper_formhash||''.split(','); let time=+new Date(); if (localFormhash[0]-time>=-86400000&&localFormhash[1]) { return localFormhash[1]; } else { let res = await get('https://bgm.tv/new_subject/4'); let doc = res.response; let formhash = $(doc).find('input[name=formhash]').attr('value'); localStorage.bgm_wikihelper_formhash = `${time},${formhash}`; return formhash } } /* 替换链接。主要是如果在a页面解析B页面结果的话,出来的的绝对连接的host部分会被替换成a链接的。 所以要换回来.currentUrl指的是当前页面获取到的错误的绝对连接,official指的是正确的链接的host部分 function replaceUrl(currentUrl,officialUrl){ return currentUrl.replace(window.location.origin,officialUrl) }*/ //搜索条目,name是条目名字,type是类型。1=Book 2=Anime 3=Music 4=Game 6=Real。默认anime /* async function searchSubject(name, type) { if (!type) { type = 2 } let url = `https://bgm.tv/subject_search/${name}?cat=${type}`; let res = await get(url); let doc = res.response; let items = $(doc).find('#browserItemList li'); if (items.length > 0) { let userConfirm = confirm("看起来已经有同名条目了,去看看吧"); if (userConfirm) { GM_openInTab(url, 'active'); let addConfirm = confirm("已经确认过是否有重复条目了,要继续添加吗?"); if (addConfirm) { //添加条目函数 } } } else { //后续添加条目函数 } } */ //type默认和charaKind值一致 //cv检测之所以用这个不用api是为了防止同名角色混乱,所以人工检验 //返回值为 是否没有重复条目 async function searchChara(name, type) { if (type == "chara") { type = 'crt' } else { type = 'prsn' } //过滤掉charaName里的特殊字符,否则部分特殊字符会影响原文搜索结果 name = stripscript(name); let url = `https://bgm.tv/mono_search/${name}?cat=${type}`; let res = await get(url); let doc = res.response; let items = $(doc).find('#columnSearchB .light_odd'); await new Promise((resolve, reject) => { if (items.length > 0) { let userConfirm = confirm("看起来已经有同名条目了,去看看吧。"); if (userConfirm) { GM_openInTab(url, false); let asked = false; document.addEventListener('visibilitychange', () => { if (!document.hidden && !asked) { if (confirm('已经确认过是否有重复条目了,要继续添加吗?')) { resolve(true) } else { //第二次选择否 reject(false) } asked = true; } }); } else { //第一次选择否 reject(false); } } else { //后续添加条目函数 resolve(true); } }) } async function relatedAllSub(obj, charaId) { for (let i in obj) { if (obj[i]) { await relatedSub(i, obj[i], charaId) } } } //角色关联主条目。subid是主条目ID,最外层relateSetting里指定,未指定则默认不关联 //角色类型(主角配角客串)一次只能设置一个值,默认主角。在全局变量里改 //目前是只关联提供的subid(也就是说是替换型关联而不是新增型关联。主要是考虑到替换条目的时候的需求) async function relatedSub(type, subid, charaId) { if (subid) { let url = `https://bgm.tv/character/${charaId}/add_related/${type}`; let subItems = subid.split(','); let infoArrlist = ''; for (let n = 0; n < subItems.length; n++) { infoArrlist += `infoArr[n${n}][crt_type]=${charaType}&infoArr[n${n}][subject_id]=${subItems[n]}&` } let data = `formhash=${formhash}&${infoArrlist}submit=保存关联数据` let res = await post(url, data) if ($(res.responseText).find('#crtRelateSubjects li').length < 1) { alert(`关联${type}失败`) } else { alert(`关联${type}成功`) } } } //新增型关联条目,会在原先关联的基础上进行条目关联 async function addRelatedAllSub(obj, charaId) { for (let i in obj) { if (obj[i]) { await addRelatedSub(i, obj[i], charaId) } } } async function addRelatedSub(type, subid, charaId) { if (subid) { let url = `https://bgm.tv/character/${charaId}/add_related/${type}`; let page=await getResBody(url); let subItems = subid.split(','); let infoArrlist = ''; let relatedItem=$(page).find('ul#crtRelateSubjects li') relatedItem.map((k,v)=>{ let type= $(v).find('select').prop('name')+'='+$(v).find('select').prop('value'); let sub= $(v).find('input').prop('name')+'='+$(v).find('input').prop('value'); infoArrlist+=`${type}&${sub}&` }); for (let n = 0; n < subItems.length; n++) { let j=n+relatedItem.length; infoArrlist += `infoArr[n${j}][crt_type]=${charaType}&infoArr[n${j}][subject_id]=${subItems[n]}&` } let data = `formhash=${formhash}&${infoArrlist}submit=保存关联数据` let res = await post(url, data) if ($(res.responseText).find('#crtRelateSubjects li').length < 1) { alert(`关联${type}失败`) } else { alert(`关联${type}成功`) } } } //查询CV条目id,仅支持全名搜索,默认取第一条 async function getCVId(name) { if (!name) { alert('未找到声优相关信息'); return false; } let url = `https://bgm.tv/json/search-cv_person/${name}`; let res = await get(url, 'json'); CVId = Object.keys(res.response)[0]; let missCV = localStorage.bgm_wikihelper_misscv; if (!missCV) { missCV = ''; } if (CVId) { return true; } else { missCV += (`,${name}`); localStorage.bgm_wikihelper_misscv = missCV; alert(`找不到该声优${name}`) return false } } //关联CV async function relatedCV(type, subid, charaId) { let subTypeId = subTypeArr.indexOf(type) + 1; let subItems = subid.split(','); let infoArrlist = ''; if (subid) { let url = `https://bgm.tv/character/${charaId}/add_related/person/${type}`; for (let n = 0; n < subItems.length; n++) { infoArrlist += `infoArr[n${n}][prsn_id]=${CVId}&infoArr[n${n}][subject_id]=${subItems[n]}&infoArr[n${n}][subject_type_id]=${subTypeId}&` } let data = `formhash=${formhash}&${infoArrlist}submit=保存关联数据` // console.log(data); // let data = `formhash=${formhash}&infoArr[n0][prsn_id]=${CVId}&infoArr[n0][subject_id]=${subid}&infoArr[n0][subject_type_id]=${subTypeId}&submit=保存关联数据` let res = await post(url, data) // console.log(res) if ($(res.responseText).find('#crtRelateSubjects li').length < 1) { alert(`${type}关联CV失败`) } else { alert(`${type}关联CV成功`) } } } //obj是最上面的关联设置,CVRelatedSetting和subRelatedSetting async function relatedAllCV(obj, charaId) { let checkCV = await getCVId(CVName); if (!checkCV) { return false; } else { for (let i in obj) { if (obj[i]) { await relatedCV(i, obj[i], charaId) } } } } //新增型cv关联 async function addRelatedCV(type, subid, charaId) { let subTypeId = subTypeArr.indexOf(type) + 1; let subItems = subid.split(','); if (subid) { let url = `https://bgm.tv/character/${charaId}/add_related/person/${type}`; let page=await getResBody(url); let infoArrlist = ''; let relatedItem=$(page).find('ul#crtRelateSubjects li') relatedItem.map((k,v)=>{ let type= $(v).find('.tip input').prop('name')+'='+$(v).find('.tip input').prop('value'); let sub= $(v).find('input').eq(1).prop('name')+'='+$(v).find('input').eq(1).prop('value'); infoArrlist+=`${type}&${sub}&` }); for (let n = 0; n < subItems.length; n++) { let j=n+relatedItem.length; infoArrlist += `infoArr[n${j}][prsn_id]=${CVId}&infoArr[n${j}][subject_id]=${subItems[n]}&infoArr[n${j}][subject_type_id]=${subTypeId}&` console.log(infoArrlist) } let data = `formhash=${formhash}&${infoArrlist}submit=保存关联数据` // console.log(data); // let data = `formhash=${formhash}&infoArr[n0][prsn_id]=${CVId}&infoArr[n0][subject_id]=${subid}&infoArr[n0][subject_type_id]=${subTypeId}&submit=保存关联数据` let res = await post(url, data) // console.log(res) if ($(res.responseText).find('#crtRelateSubjects li').length < 1) { alert(`${type}关联CV失败`) } else { alert(`${type}关联CV成功`) } } } async function addRelatedAllCV(obj, charaId) { let checkCV = await getCVId(CVName); if (!checkCV) { return false; } else { for (let i in obj) { if (obj[i]) { await addRelatedCV(i, obj[i], charaId) } } } } //角色排序,subid为角色关联的条目id,sortNo是角色排序的序号,未指定的话默认当前角色类型末尾 async function charaSort(subId,sortNo){ let url=`https://bgm.tv/subject/${subId}/add_related/character`; let sortPage=await get(url); let charaSortArr=$(sortPage.response).find('#crtRelateSubjects li'); // console.log(charaSortArr) let order; if(typeof(sortNo)=='string'){ return false; } if(isNaN(sortNo)){ order=$(charaSortArr).find(`option[value="${charaType}"]:selected`).length; }else{ order=sortNo; } // console.log(order); let sortData=''; charaId=charaId; charaSortArr.map((k,v)=>{ // console.log(v); let crtType=$(v).find(`select`).prop('value'); let crtOrder=$(v).find('input.item_sort').prop('value'); let crtId=$(v).find('.title a').prop('href').split('/').pop(); // console.log(crtId) // console.log(charaId); if(crtId==charaId){ sortData+=`infoArr[${k}][crt_type]=${crtType}&infoArr[${k}][crt_order]=${order}&infoArr[${k}][crt_id]=${charaId}&`; }else{ sortData+=`infoArr[${k}][crt_type]=${crtType}&infoArr[${k}][crt_order]=${crtOrder}&infoArr[${k}][crt_id]=${crtId}&` } }); // console.log(sortData); // let data=`formhash=${formhash}&submit=保存关联数据${sortData}`; // data=encodeURI(data); //sortdata的位置会影响encode的必要性。如果将其放在submit后面的话则必须encode。 //目前还不知道原因。 let data=`formhash=${formhash}&${sortData}submit=保存关联数据`; // data=encodeURI(data); let res=await post(url,data); // console.log(res); if(res.status!=='200'){ // alert('排序失败'); // await charaSort(subId,sortNo); } } async function sortAllSub(obj,charaId,sortNo){ for (let i in obj) { if (obj[i]) { let subArr=obj[i].split(','); for(let n=0;n<subArr.length;n++){ await charaSort(subArr[n],sortNo) } } } } //根据名字从谷歌cse找图片,默认取第一个结果。别问我为什么不直接取谷歌图片的结果.stie填域名即可。比如twitter.com //搜索引擎:https://cse.google.com/cse?cx=016521770207998520683:b6l6luja61k async function getImageUrlFromGoogle(name,site) { if(!site){ site=''; } let cxID = '016521770207998520683:b6l6luja61k'; let apiKey = 'AIzaSyDoTuZttbaby57Cf-DLvdAX6WkzM4uWzOs'; let baseurl = `https://www.googleapis.com/customsearch/v1?key=${apiKey}&cx=${cxID}&q=${name}&siteSearch=${site}&searchType=image&gl=jp&cr=countryJP&alt=json`; let result = await get(baseurl, 'json'); let imageUrl; try { imageUrl = result.response.items[0].link || ''; return imageUrl; } catch (e) { let usrselect=window.confirm('头像搜索失败,尝试再次搜索吗'); if(usrselect){ getImageUrlFromGoogle(name); }else{ return `https://bgm.tv/img/info_only.png`; } } } /* 从别的网站获取图片,返回图片链接。 url必须是是图片来源网站,带http头的绝对链接;selector是图片所在选择器,不是jquery对象*/ async function getImageUrlFromSite(url,selector){ let resPage=await get(url); // console.log(resPage); let imgUrl=$(resPage.responseText).find(selector).prop('src') return imgUrl; } function cropImage(img){ let image=new Image(); image.src=URL.createObjectURL(img); return new Promise((res,rej)=>{ image.onload=function(){ URL.revokeObjectURL(this.src); var canvas=document.createElement('canvas'); canvas.width=cropSetting[2]; canvas.height=cropSetting[3]; let cw=canvas.width; let ch=canvas.height; let ctx=canvas.getContext('2d'); ctx.drawImage(this,cropSetting[0],cropSetting[1],cw,ch,0,0,cw,ch) canvas.toBlob(function(blob){ img=blob; // console.log(img) res(img) return img },img.type) } }) } async function ImagetoBlob(url) { //必须res然后res.response,否则会读不到文件 if(!url){ url='https://bgm.tv/img/info_only.png'; } let res = await get(url, 'blob'); if (res.status!==200){ charaAvatarImage=new Blob() }else{ charaAvatarImage = res.response; if(cropSetting.length>0){ charaAvatarImage=await cropImage(charaAvatarImage) // console.log(charaAvatarImage) } } return charaAvatarImage } //table是某个jquery表格对象。比如$('table.indexbox')这样 //从萌百页面右边的表格里获取信息 //萌百的表格和wiki的构造不一样,没有th标签 async function moeTable2InfoTpl(table) { table ? table : (infoTplDetail = null); let items = table.find('tr'); let avatar = items.find('img'); CVName ?CVName:CVName= table.find('tr:contains("声优")').children().eq(1).text().replace('\n', '') || null; console.log(`声优为${CVName}`) if (!charaAvatarUrl) { if (avatar.length) { charaAvatarUrl = avatar[0].src; } else { charaAvatarUrl = await getImageUrlFromGoogle(charaName); } } console.log(`头像链接:${charaAvatarUrl}`); kana = items.find('rt').append(' ').text(); let linkArr = window.location.href.split('/'); chnName = decodeURI(linkArr[linkArr.length - 1]); if(!charaName){ let charaNameTmp=''; charaNameTmp = (table.find('tr:contains("名")').eq(0).children().eq(1).text()); if (charaNameTmp.indexOf('(') >= 0) { charaName = charaNameTmp.split('(')[0] } else { charaName = charaNameTmp.split('(')[0] } if (!charaName) { charaName = chnName } } try { romaji = table.find('tr:contains("名")').eq(0).children().eq(1).text().split('(')[1].split(')')[0]; // romaji = romajiTemp.match(/(([^)]*))/)[1] || romajiTemp.match(/\(([^)]*)\)/)[1]; } catch (e) { romaji = '' } //姓名信息已经由上面获取,所以删掉这一行。 items.find('td:contains("姓名")').parent('tr').remove(); //萌百词条没有强制保准,导致有的假名是上标有的是放在本名里。 items.find('th:contains("本名")').parent('tr').remove(); //删除出道角色代表角色等信息 table.find('tr:contains("角色")').remove(); table.find('tr:contains("声优")').remove(); table.find('tr:contains("萌点")').remove(); table.find('sup').remove(); items = table.find('tr'); items.map(k => { let infoName = $(items[k]).children()[0].innerText.replace('\n', '/'); let infoDetail; if ($(items[k]).children().length > 1) { infoDetail = $(items[k]).children()[1].innerText.replace('\n', '/'); // console.log('infoDetail='+infoDetail) } if (infoName && infoDetail) { infoTplDetail += `|${infoName}=${infoDetail}\r\n`; } }); // console.log(`infoTplDetail=${infoTplDetail}`) return infoTplDetail; } //table是某个jquery表格对象。比如$('table.indexbox')这样 //从日文wiki页面右边的表格里获取信息 async function wikiTable2InfoTpl(table) { table ? table : (infoTplDetail = null); let items = table.find('tr'); let avatar = items.eq(1).find('img'); // console.log(avatar); if (!charaAvatarUrl) { if (avatar.length) { charaAvatarUrl = avatar[0].src; } else { charaAvatarUrl = await getImageUrlFromGoogle(charaName); } } // console.log(charaAvatarUrl); kana = items.find('th').children('span').eq(0).text() items.map(k => { let infoName = $(items[k]).find('th').text(); //生日的隐藏span以及引用出处的上标必须先删掉 $(items[k]).find('td').children('span').remove() $(items[k]).find('td').children('sup').remove() let infoDetail if ($(items[k]).find('td').length > 0) { infoDetail = $(items[k]).find('td')[0].innerText.replace('\n', '/'); } if (infoName && infoDetail) { infoTplDetail += `|${infoName}=${infoDetail}\r\n`; } }); console.log(`infoTplDetail=${infoTplDetail}`) return infoTplDetail; } /*body是一个jquery对象。这里的话就是请求到的wiki页面本身.如果不指定的话默认就是'body'. 功能是从wiki和萌百页面获取名字、个人简介(charaInfo)和infoTplDetal*/ async function cvInfoFromWiki(body) { body ? body : body = 'body'; //不从表格拿是因为不是所有条目都有表格 if (!charaName) { let linkArr = window.location.href.split('/'); charaName = decodeURI(linkArr[linkArr.length - 1]); } //寻找声优简介信息并删除上标号 let descP = $(body).find('#toc').prevAll('p'); let cvDesc = []; descP.map(i => { descP.eq(i).find('sup').remove(); cvDesc.unshift(descP[i].innerText); }) charaInfo = cvDesc.join().replace(' ', ''); //将边上的表格信息整合成infoTpl,边上没有表格的话直接为空 let table = $(body).find('table.infobox'); if (pageHost.indexOf('moegirl.org') < 0) { await wikiTable2InfoTpl(table); } else { await moeTable2InfoTpl(table); } } async function charaInfoFromWiki(body) { body ? body : body = 'body'; //不从表格拿是因为不是所有条目都有表格 //寻找简介信息并删除黑条 let descP = $(body).find('.mw-parser-output').children('h2').eq(0).nextUntil(":not(p)"); let charaDesc = []; descP.map(i => { descP.eq(i).find('.heimu').remove(); descP.eq(i).find('sup').remove(); charaDesc.push(descP[i].innerText); }) charaInfo = charaDesc.join().replace(' ', ''); //将边上的表格信息整合成infoTpl,边上没有表格的话直接为空 let table = $(body).find('.mw-parser-output table').eq(0); //萌百词条的表格两套html模板,角色和wiki 的声优表格类似 await moeTable2InfoTpl(table); } //生成需要提交用户信息body,无参数的时候默认chara,大小写皆可。其他时候需要和charaKindArr一致 async function makeFormData(subtype) { //新增条目类型。目前有chara,cv等,默认chara。这个主要是formdata的数据结构 charaAvatarImage = await ImagetoBlob(charaAvatarUrl); var subOpt = { 'chara': { formhash: formhash, crt_name: charaName, crt_infobox: infoTpl, crt_summary: charaInfo, }, 'person': { formhash: formhash, crt_name: charaName, crt_infobox: infoTpl, crt_summary: charaInfo, }, }; subtype ? subtype : subtype = 'chara'; subtype = subtype.toLowerCase(); if (subtype !== 'chara') { subOpt['person'][`prsn_pro[${subtype}]`] = 1; subtype = 'person' } let fd = new FormData(); //console.log(charaAvatarImage); Object.entries(subOpt[subtype]).map(obj => { fd.append(obj[0], obj[1]) }); return fd } //获取特定条目下关联的所有角色名称.id可以是数组,比如[1,2] async function getRelatedCharas(id){ let subjects=id.toString().split(','); let relatedCharas={}; for(let i in subjects){ let url=`https://bgm.tv/subject/${subjects[i]}/characters`; let page=await getResBody(url); let charas=$(page).find('.mainWrapper .light_odd h2 a'); charas.map((k,v)=>{ let name=$(v).text(); let id=$(v).attr('href').split('/character/')[1]; relatedCharas[name]=id }) // relatedCharas+=names.append('||&*').text(); // console.log(relatedCharas) } // relatedCharas=(relatedCharas.split('||&*')); // relatedCharas.splice(-1,1); return relatedCharas } //subtype为chara或者其他charaKindArr里的值,不能为空 //editmode是编辑条目,参数类型给人物条目id,为空的情况下默认添加模式 //nosort指添加完后角色不做排序(大量角色的时候排序很浪费时间.默认排序 async function addSubject(subtype, editmode,sortNum) { //如果不检查重复以及开启静默模式的话,不会有任何的弹窗 if(!checkDupe&&silent){ window.alert=console.log; window.confirm=()=>false; } subtype = subtype.toLowerCase(); let isNODupe=true; if (checkDupe) { await searchChara(charaName, subtype) .then(e => { isNODupe = true }) .catch(e => { alert('取消添加') isNODupe = false }); } if (isNODupe) { let urlPath, url; if (subtype == 'chara') { urlPath = 'character' } else { urlPath = 'person' } let fd = await makeFormData(subtype); //单独拿出来是因为传参的方式加进去的不是file类型而是普通blob,没法被服务器端识别 fd.append('picfile', charaAvatarImage, 'new.png'); if (!editmode) { url = `https://bgm.tv/${urlPath}/new`; fd.append('crt_role', charaRole); fd.append('submit', '添加新人物'); } else { url = `https://bgm.tv/${urlPath}/${editmode}/edit`; // let imgFile=new File([charaAvatarImage],'new.png',{type:'image/png'}) // let imgblob=new Blob(charaAvatarImage,{type: 'application/octet-stream'}); fd.append('editSummary', 'bgm_wikihelper脚本替换条目'); fd.append('submit', '改好了'); } if (debugFlg) { alert(`调试模式中,不会加条目,请手动关闭后刷新页面`) for (let pair of fd.entries()) { console.log(pair[0] + ', ' + pair[1]); } } else { let pageres = await post(url, fd, 'fd'); // console.log(pageres); let tmp = pageres.finalUrl.split('/'); charaId = tmp[tmp.length - 1]; if (subtype == 'chara') { await relatedAllSub(subRelatedSetting, charaId); await relatedAllCV(CVRelatedSetting, charaId); await sortAllSub(subRelatedSetting,charaId,sortNum); } if (charaId.match(/\d+/g)) { let cfm = confirm(`${editmode?'编辑':'添加'}成功!条目id=${charaId},要去看看吗`); if (cfm) { GM_openInTab(pageres.finalUrl, 'false') } } else { alert('添加失败') }; return charaId; } } } var charaId, formhash, kana, jpnName,nickName, chnName, CVId, userFormData,CVName,pageHost, anotherName, charaName, charaAvatarUrl, charaAvatarImage, charaInfo,infoTpl, infoTplDetail = ''; var artist,romaji, color, birthday,sex,part, instrument,height, weight, zodiacSign, hobby,hate,school, bwh, age, blood, grade, like, trick, weak, unit,weapon; var subRelatedSetting ,CVRelatedSetting ,charaType ,charaKindArr ,charaKind ,charaRole ,checkDupe ,debugFlg ,editSubId ; var silent,sortNum,cropSetting=[]; var subTypeArr = ['book', 'anime', 'music', 'game', 'unkown', 'real'];