UNPKG

koishi-plugin-pixluna

Version:
5 lines 35.6 kB
import{Logger as e,Schema as t,h as n}from"koishi";import r from"wasm-vips";import{createHash as i,webcrypto as a}from"node:crypto";const o={};let s=-1;function c(e,t=`pixluna`){let n=o[t]||e.logger(t);return s>=0&&(n.level=s),o[t]=n,n}function l(e){for(let t in s=e,o)o[t].level=e}var u=class{pool;limit;constructor(e){this.pool=[],this.limit=e}add(e){let t=Array.isArray(e)?e:[e];for(let e of t)this.pool.push(e);return this}async run(){let e=[];for(let t=0;t<this.pool.length;t+=this.limit){let n=this.pool.slice(t,t+this.limit);e.push(...await Promise.all(n))}return e}};async function d(e,t,n){return await n()}async function f(e){if(e.length<12)return null;if(e[0]===255&&e[1]===216&&e[2]===255)return`image/jpeg`;if(e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71)return`image/png`;if(e[0]===71&&e[1]===73&&e[2]===70)return`image/gif`;if(e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70&&e[8]===87&&e[9]===69&&e[10]===66&&e[11]===80)return`image/webp`;if(e[0]===66&&e[1]===77)return`image/bmp`;if(e.length>=12){let t=e.slice(4,12).toString(`ascii`);if(t===`ftypavif`||t===`ftypavis`)return`image/avif`}return null}const p=r({dynamicLibraries:[]}).then(e=>(e.concurrency(1),e.Cache.max(0),e));let m=null;async function h(){return m||=await p,m}function g(e){return Math.max(0,Math.min(9,e.imageProcessing.compressionLevel??6))}function _(e){switch(e){case`horizontal`:return 1;case`vertical`:return 2;case`both`:return 3;default:return 0}}async function v(e,t,n,r){let i=await h(),a=null,o=[];try{a=i.Image.newFromBuffer(t);let e=a;if(n.imageProcessing.isFlip){let t=_(n.imageProcessing.flipMode);if(t===1){let t=e.flipHor();o.push(t),e=t}else if(t===2){let t=e.flipVer();o.push(t),e=t}else if(t===3){let t=e.flipHor();o.push(t);let n=t.flipVer();o.push(n),e=n}}if(n.imageProcessing.confusion){let t=Math.floor(Math.random()*e.width),n=Math.floor(Math.random()*e.height),r=e.getpoint(t,n);for(let e=0;e<r.length;e++)r[e]+=r[e]<255?1:-1;let a=i.Image.black(1,1);o.push(a);let s=a.newFromImage(r);o.push(s);let c=e.insert(s,t,n);o.push(c),e=c}let r=g(n),s=e.writeToBuffer(`.png`,{compression:r});return Buffer.from(s)}catch(n){return e.logger?.warn?.(`processImage: decode failed, return original buffer`,{err:n}),t}finally{for(let e=o.length-1;e>=0;e--)o[e]?.[Symbol.dispose]?.();a&&a[Symbol.dispose]?.()}}function y(e){if(e.length<=1)return[...e];let t=[...e],n=new Uint32Array(t.length);a.getRandomValues(n);for(let e=t.length-1;e>0;e--){let r=n[e]%(e+1);[t[e],t[r]]=[t[r],t[e]]}return t}const b=`__PIXLUNA_PROVIDERS__`;function x(){let e=globalThis;return e[b]||(e[b]=new Map),e[b]}function S(e,t){let n=x(),r=Array.isArray(e)?e:[e];for(let e of r){let r=String(e).trim();if(!r)continue;let i=n.get(r);(!i||i!==t)&&n.set(r,t)}}function C(e){return x().get(e)}function w(){let e=x();return Array.from(e.keys())}var T=class{static description;config;ctx;constructor(e,t){this.ctx=e,this.config=t}};S(`danbooru`,class extends T{static description=`通过 Danbooru API 获取图片`;endpoint=`https://danbooru.donmai.us`;keyPairs=[];setConfig(e){this.config=e,e.danbooru?.keyPairs?.length&&(this.keyPairs=e.danbooru.keyPairs)}get keyPair(){return this.keyPairs.length?this.keyPairs[Math.floor(Math.random()*this.keyPairs.length)]:null}async getMetaData({context:e},t){try{let n=this.keyPair,r=``;t.tag&&(r=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let i={tags:r,random:!0,limit:1,...n?{login:n.login,api_key:n.apiKey}:{}};this.config.isR18&&t.r18?i.tags+=` rating:explicit`:i.tags+=` rating:safe`;let a=await e.http.get(`${this.endpoint}/posts.json`,{params:i,proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!Array.isArray(a)||a.length===0)return{status:`error`,data:Error(`No image data returned`)};let o=a[0],s=this.config.imageProcessing.compress?o.large_file_url:o.file_url,c={id:o.id,title:``,author:o.tag_string_artist.replace(/_/g,` `),r18:o.rating===`e`||o.rating===`q`,tags:o.tag_string.split(` `),extension:o.file_url.split(`.`).pop(),aiType:0,uploadDate:new Date(o.created_at).getTime(),urls:{original:o.file_url,regular:o.large_file_url}};return $.debug(`成功获取图片元数据`,{metadata:c}),{status:`success`,data:{url:s,urls:{regular:o.large_file_url,original:o.file_url},raw:c}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://danbooru.donmai.us`}}}),S(`e621`,class extends T{static description=`通过 E621 API 获取图片`;endpoint=`https://e621.net`;keyPairs=[];setConfig(e){this.config=e,e.e621?.keyPairs?.length&&(this.keyPairs=e.e621.keyPairs)}get keyPair(){return this.keyPairs.length?this.keyPairs[Math.floor(Math.random()*this.keyPairs.length)]:null}async getMetaData({context:e},t){try{let n=this.keyPair,r=``;t.tag&&(r=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let i={tags:`${r} order:random`,limit:1};this.config.isR18&&t.r18?i.tags+=` -rating:s`:i.tags+=` rating:s`;let a={"User-Agent":`PixLuna/1.0`};n&&(a.Authorization=`Basic `+Buffer.from(`${n.login}:${n.apiKey}`).toString(`base64`));let o=await e.http.get(`${this.endpoint}/posts.json`,{params:i,headers:a,proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!Array.isArray(o.posts)||o.posts.length===0)return{status:`error`,data:Error(`No image data returned`)};let s=o.posts[0],c=this.config.imageProcessing.compress?s.sample.url:s.file.url,l={id:s.id,title:``,author:s.tags.artist.join(`, `),r18:s.rating!==`s`,tags:[...s.tags.general,...s.tags.artist],extension:s.file.url.split(`.`).pop(),aiType:0,uploadDate:new Date(s.created_at).getTime(),urls:{original:s.file.url,regular:s.sample.url}};return $.debug(`成功获取图片元数据`,{metadata:l}),{status:`success`,data:{url:c,urls:{regular:s.sample.url,original:s.file.url},raw:l}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://e621.net`}}}),S(`gelbooru`,class extends T{static description=`通过 Gelbooru API 获取图片`;endpoint=`https://gelbooru.com/index.php`;get keyPair(){let e=this.config.gelbooru?.keyPairs||[];return e.length?e[Math.floor(Math.random()*e.length)]:null}async getMetaData({context:e},t){let n=``;t.tag&&(n=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let r=new URLSearchParams({page:`dapi`,s:`post`,q:`index`,json:`1`,limit:`1`,tags:`${n} sort:random${this.config.isR18&&t.r18?``:` rating:safe`}`}),i=this.keyPair;i&&r.append(`api_key`,i.apiKey);let a=`${this.endpoint}?${r.toString()}`;try{let t=await e.http.get(a,{proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!t.post?.length)return{status:`error`,data:Error(`No image data returned`)};let n=t.post[0],r={id:n.id,title:n.source||`Gelbooru - ${n.id}`,author:n.owner.replace(/_/g,` `),r18:[`explicit`,`questionable`].includes(n.rating),tags:n.tags.split(` `),extension:n.file_url.split(`.`).pop(),uploadDate:new Date(n.created_at).getTime(),aiType:0,urls:{original:n.file_url,regular:n.sample_url}};return $.debug(`成功获取图片元数据`,{metadata:r}),{status:`success`,data:{url:this.config.imageProcessing.compress?n.file_url:n.sample_url,urls:{regular:n.sample_url,original:n.file_url},raw:r}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://gelbooru.com/`}}setConfig(e){this.config=e}}),S(`konachan`,class extends T{static description=`通过 Konachan API 获取图片`;endpoint=`https://konachan.com`;keyPairs=[];hashPassword(e){let t=`So-I-Heard-You-Like-Mupkids-?--${e}--`,n=i(`sha1`);return n.update(t),n.digest(`hex`)}setConfig(e){this.config=e,e.konachan?.keyPairs?.length&&(this.keyPairs=e.konachan.keyPairs)}get keyPair(){if(!this.keyPairs.length)return null;let e=this.keyPairs[Math.floor(Math.random()*this.keyPairs.length)];return{login:e.login,password_hash:this.hashPassword(e.password)}}async getMetaData({context:e},t){try{let n=this.keyPair,r=``;t.tag&&(r=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let i={tags:`order:random ${r}`.trim(),limit:1,api_version:2,...n&&{login:n.login,password_hash:n.password_hash,auth:!0}};this.config.isR18&&t.r18?i.tags=`${i.tags} rating:questionable rating:explicit`.trim():i.tags=`${i.tags} rating:safe`.trim(),$.debug(`请求参数`,i);let a=await e.http.get(`${this.endpoint}/post.json`,{params:i,proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!Array.isArray(a)||a.length===0)return{status:`error`,data:Error(`No image data returned`)};let o=a[0],s=this.config.imageProcessing.compress?o.sample_url:o.file_url,c={id:o.id,title:``,author:o.author.replace(/_/g,` `),r18:o.rating===`e`||o.rating===`q`,tags:o.tags.split(` `),extension:o.file_url.split(`.`).pop(),aiType:0,uploadDate:new Date(o.created_at).getTime(),urls:{original:o.file_url,regular:o.sample_url}};return $.debug(`成功获取图片元数据`,{metadata:c}),{status:`success`,data:{url:s,urls:{regular:o.sample_url,original:o.file_url},raw:c}}}catch(e){return $.error(`Konachan请求失败`,e),{status:`error`,data:e}}}getMeta(){return{referer:`https://konachan.com`}}});function E(e){let t=`--${e}--`,n=i(`sha1`);return n.update(t),n.digest(`hex`)}S(`lolibooru`,class extends T{static description=`通过 Lolibooru API 获取图片`;endpoint=`https://lolibooru.moe`;keyPairs=[];setConfig(e){this.config=e,e.lolibooru?.keyPairs?.length&&(this.keyPairs=e.lolibooru.keyPairs)}get keyPair(){if(!this.keyPairs.length)return null;let e=this.keyPairs[Math.floor(Math.random()*this.keyPairs.length)];return{login:e.login,password_hash:E(e.password)}}async getMetaData({context:e},t){try{let n=this.keyPair,r=``;t.tag&&(r=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let i={tags:`${r} order:random`,limit:`1`};this.config.isR18&&t.r18?i.tags+=` -rating:s`:i.tags+=` rating:s`,n&&(i.login=n.login,i.password_hash=n.password_hash);let a=await e.http.get(`${this.endpoint}/post/index.json`,{params:i,proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!Array.isArray(a)||a.length===0)return{status:`error`,data:Error(`No image data returned`)};let o=a[0],s=this.config.imageProcessing.compress?o.sample_url:o.file_url,c={id:o.id,title:o.source||`Lolibooru - ${o.id}`,author:o.author.replace(/_/g,` `),r18:[`e`,`q`].includes(o.rating),tags:o.tags.split(` `),extension:o.file_url.split(`.`).pop(),aiType:0,uploadDate:new Date(o.created_at).getTime(),urls:{original:encodeURI(o.file_url),regular:encodeURI(o.sample_url)}};return $.debug(`成功获取图片元数据`,{metadata:c}),{status:`success`,data:{url:encodeURI(s),urls:{regular:encodeURI(o.sample_url),original:encodeURI(o.file_url)},raw:c}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://lolibooru.moe`}}});var D=class extends T{constructor(e,t){super(e,t),this.ctx=e,this.config=t}async getMetaData({context:e},t){let n=[];t.tag&&(n=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean));let r={r18:this.config.isR18&&t.r18?1:0,num:1,size:t.size,keyword:n.length===0?t.tag:void 0,tag:n.length>0?n:void 0,excludeAI:t.excludeAI,proxy:t.proxy},i=await e.http.post(this.API_URL,r,{proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(i.error||!i.data||i.data.length===0)return{status:`error`,data:Error(i.error||`No image data returned`)};let a=i.data[0],o=this.config.imageProcessing.compress?a.urls.original:a.urls.regular||a.urls.original,s={id:a.pid,title:a.title,author:a.author,r18:a.r18,tags:a.tags,extension:a.ext,aiType:a.aiType,uploadDate:a.uploadDate,urls:a.urls};return $.debug(`成功获取图片元数据`,{metadata:s}),{status:`success`,data:{url:o,urls:{regular:a.urls.regular,original:a.urls.original},raw:s}}}setConfig(e){this.config=e}getMeta(){return{referer:`https://www.pixiv.net/`}}},O=class extends D{static description=`通过 Lolisuki API 获取图片`;API_URL=`https://lolisuki.cn/api/setu/v1`},k=class extends D{static description=`通过 Lolicon API 获取图片`;API_URL=`https://api.lolicon.app/setu/v2`};S(`lolisuki`,O),S(`lolicon`,k);function A(e,t){let r=[n.image(e.data,e.mimeType),n(`text`,{content:`\ntitle:${e.title}\n`}),n(`text`,{content:`id:${e.id}\n`})];return t?.showTags!==!1&&r.push(n(`text`,{content:`tags:${e.tags.map(e=>`#${e}`).join(` `)}\n`})),n(``,r)}function j(e,t){return n(``,[n(`at`,{id:e}),n(`text`,{content:` ${t}`})])}function ee(e,t){let r=[],i=e[0];return r.push(n(`text`,{content:`title:${i.title}\n`}),n(`text`,{content:`id:${i.id}\n`}),n(`text`,{content:`共 ${e.length} 页\n\n`})),t?.showTags!==!1&&r.push(n(`text`,{content:`tags:${i.tags.map(e=>`#${e}`).join(` `)}\n\n`})),e.forEach((e,t)=>{r.push(n(`text`,{content:`第 ${t+1} 页:\n`}),n.image(e.data,e.mimeType),n(`text`,{content:` `}))}),n(``,r)}async function M(e,t=0,n=!0){(!n||t>0)&&await new Promise(t=>setTimeout(t,e.apiDelay))}function N(e){return e?e.split(/[,,]/).map(e=>e.trim()).filter(Boolean).slice(0,5):[]}function P(e,t){if(!t.length)return!0;let n=e.title?.toLowerCase()||``,r=Array.isArray(e.tags)?e.tags.map(e=>typeof e==`string`?e.toLowerCase():e.tag?.toLowerCase()||``):[];return t.every(e=>{let t=e.toLowerCase();return n.includes(t)||r.some(e=>typeof e==`string`&&e.includes(t))})}function F(e,t){if(!t.length||!e.length)return e;for(let n=t.length;n>0;n--){let r=t.slice(0,n),i=e.filter(e=>P(e,r));if(i.length>0)return i}return e}var I=class extends T{getHeaders(){return{Referer:`https://www.pixiv.net/`,"User-Agent":V,Cookie:`PHPSESSID=${this.config.pixiv.phpSESSID}`}}getProxyAgent(){return this.config.isProxy?this.config.proxyHost:void 0}constructImageUrl(e){let t=this.config.baseUrl||`i.pximg.net`;return e.replace(`i.pximg.net`,t)}async fetchPixivData(e,t){return await e.http.get(t,{headers:this.getHeaders(),proxyAgent:this.getProxyAgent()})}setConfig(e){this.config=e}getMeta(){return{referer:`https://www.pixiv.net/`}}},L=class e extends I{static DISCOVERY_URL=`https://www.pixiv.net/ajax/illust/discovery`;static ILLUST_PAGES_URL=`https://www.pixiv.net/ajax/illust/{ARTWORK_ID}/pages`;async getMetaData({context:t},n){try{let r=N(n.tag),i=`${e.DISCOVERY_URL}?mode=${this.config.isR18&&n.r18?`r18`:`all`}&limit=20`,a=await this.fetchPixivData(t,i);if(a.error||!a.body.illusts.length)return{status:`error`,data:Error(a.message||`未找到插画`)};let o=F(a.body.illusts,r);if(this.config.isR18||(o=o.filter(e=>!(e.xRestrict>0||e.tags.some(e=>e.toLowerCase()===`r-18`)))),o.length===0)return{status:`error`,data:Error(`未找到包含标签 "${r.join(`, `)}" 的插画`)};let s=y(o)[0],c=e.ILLUST_PAGES_URL.replace(`{ARTWORK_ID}`,s.id),l=await t.http.get(c,{headers:this.getHeaders(),proxyAgent:this.getProxyAgent()});if(l.error||!l.body.length)return{status:`error`,data:Error(`无法获取原图链接`)};let u=this.config.baseUrl||`i.pximg.net`,d=l.body[0].urls.original.replace(`i.pximg.net`,u),f={id:parseInt(s.id,10),title:s.title,author:s.userName,r18:s.xRestrict>0,tags:s.tags,extension:d.split(`.`).pop(),aiType:0,uploadDate:new Date(s.createDate).getTime(),urls:{original:d,regular:s.url.replace(`i.pximg.net`,u)}};return{status:`success`,data:{url:d,urls:f.urls,raw:f}}}catch(e){return $.error(`获取 Pixiv Discovery 元数据失败`,{error:e}),{status:`error`,data:e}}}},R=class e extends I{static description=`获取 Pixiv 已关注画师作品,需要 Pixiv 账号`;static FOLLOWING_URL=`https://www.pixiv.net/ajax/user/{USER_ID}/following?offset={OFFSET_COUNT}&limit={LIMIT_COUNT}&rest=show`;static USER_PROFILE_URL=`https://www.pixiv.net/ajax/user/{USER_ID}/profile/all`;static ILLUST_URL=`https://www.pixiv.net/ajax/illust/{ARTWORK_ID}`;async getMetaData({context:e},t){if(!this.config.pixiv.phpSESSID)return{status:`error`,data:Error(`未设置 Pixiv PHPSESSID`)};let n=N(t?.tag);try{let t=await this.getAllFollowingUsers(e);if(!t.length)return{status:`error`,data:Error(`未找到关注的用户`)};let r=[],i=new Set,a=0,o=Math.min(t.length,10),s=y(t);for(;a<o&&r.length<20;){await M({...this.config},a);let t=s[a];if(a++,i.has(t.userId))continue;i.add(t.userId);let o=await this.getUserProfile(e,t.userId);if(o.error||!o.body.illusts)continue;let c=Object.entries(o.body.illusts).map(([e,t])=>({id:e,...t}));if(n.length>0)for(let t of c)try{await M(this.config,0,!1);let i=await this.getIllustDetail(e,t.id);if(!i.error&&i.body){let e=i.body.xRestrict>0||i.body.tags.tags.some(e=>e.tag.toLowerCase()===`r-18`);(this.config.isR18||!e)&&P(i.body,n)&&r.push(i.body)}}catch{}else break}if(n.length>0&&r.length>0){let e=y(r)[0];return{status:`success`,data:{url:this.constructImageUrl(e.urls.original),urls:{original:this.constructImageUrl(e.urls.original)},raw:{id:parseInt(e.id,10),title:e.title,author:e.userName,r18:e.xRestrict>0,tags:e.tags.tags.map(e=>e.tag),extension:e.urls.original.split(`.`).pop(),aiType:0,uploadDate:new Date(e.createDate).getTime(),urls:{original:this.constructImageUrl(e.urls.original)}}}}}else if(n.length>0&&r.length===0)return{status:`error`,data:Error(`未找到包含标签 "${n.join(`, `)}" 的插画`)};else{let n=y(t)[0],r=await this.getUserProfile(e,n.userId);if(r.error||!r.body.illusts)return{status:`error`,data:Error(`无法获取用户作品列表`)};let i=Object.keys(r.body.illusts),a,o=0,s=i.length;do{await M(this.config,o);let t=y(i)[0];if(a=await this.getIllustDetail(e,t),o++,a.error||!a.body){if(o>=s)return{status:`error`,data:Error(`无法获取合适的插画详情`)};continue}let n=a.body.xRestrict>0||a.body.tags.tags.some(e=>e.tag.toLowerCase()===`r-18`);if(!this.config.isR18&&n)continue;break}while(o<s);if(o>=s)return{status:`error`,data:Error(`未找到符合条件的插画`)};let c=a.body;return{status:`success`,data:{url:this.constructImageUrl(c.urls.original),urls:{original:this.constructImageUrl(c.urls.original)},raw:{id:parseInt(c.id,10),title:c.title,author:c.userName,r18:c.xRestrict>0,tags:c.tags.tags.map(e=>e.tag),extension:c.urls.original.split(`.`).pop(),aiType:0,uploadDate:new Date(c.createDate).getTime(),urls:{original:this.constructImageUrl(c.urls.original)}}}}}}catch(e){return $.error(`获取 Pixiv Discovery 元数据失败`,{error:e}),{status:`error`,data:e}}}async getAllFollowingUsers(t){let n=0,r=[];for(;;){await M(this.config,n);let i=e.FOLLOWING_URL.replace(`{USER_ID}`,this.config.pixiv.userId).replace(`{OFFSET_COUNT}`,n.toString()).replace(`{LIMIT_COUNT}`,`100`),a=await this.fetchPixivData(t,i);if(a.error||!a.body.users.length||(r.push(...a.body.users),n+=100,a.body.users.length<100))break}return r}async getUserProfile(t,n){let r=e.USER_PROFILE_URL.replace(`{USER_ID}`,n);return await this.fetchPixivData(t,r)}async getIllustDetail(t,n){let r=e.ILLUST_URL.replace(`{ARTWORK_ID}`,n);return await this.fetchPixivData(t,r)}},z=class e extends I{static description=`通过作品ID获取Pixiv图片`;static ILLUST_URL=`https://www.pixiv.net/ajax/illust/{ARTWORK_ID}`;async getImageByPid(e,t,n=0){if(!this.config.pixiv.phpSESSID)return{status:`error`,data:Error(`未设置 Pixiv PHPSESSID`)};try{let r=await this.getIllustDetail(e,t);if(r.error||!r.body)return{status:`error`,data:Error(`无法获取插画详情`)};let i=r.body,a=i.urls.original.split(`_p`);if(a.length!==2)return{status:`error`,data:Error(`图片URL格式错误`)};let o=`${a[0]}_p${n}${a[1].substring(a[1].indexOf(`.`))}`;if(n>=i.pageCount)return{status:`error`,data:Error(`页码超出范围,该作品共有 ${i.pageCount} 页`)};let s={id:parseInt(i.id,10),title:i.title,author:i.userName,r18:i.xRestrict>0,tags:i.tags.tags.map(e=>e.tag),extension:o.split(`.`).pop(),aiType:0,uploadDate:new Date(i.createDate).getTime(),urls:{original:this.constructImageUrl(o)}};return $.debug(`成功获取 Pixiv 图片元数据`,{metadata:s}),{status:`success`,data:{url:s.urls.original,urls:s.urls,raw:s}}}catch(e){return $.error(`获取 Pixiv 图片元数据失败`,{error:e}),{status:`error`,data:e}}}async getIllustDetail(t,n){let r=e.ILLUST_URL.replace(`{ARTWORK_ID}`,n);return await t.http.get(r,{headers:this.getHeaders(),proxyAgent:this.getProxyAgent()})}async getMetaData(){return{status:`error`,data:Error(`This provider only supports getting images by ID`)}}async getImageWithBuffer(e,t=0){let n=await this.getImageByPid(this.ctx,e,t);if(n.status===`error`)throw n.data;let[r,i]=await H(this.ctx,this.config,n.data.url,this);return{data:Buffer.from(r),mimeType:i,id:n.data.raw.id,title:n.data.raw.title,tags:n.data.raw.tags,author:n.data.raw.author,r18:n.data.raw.r18,extension:n.data.raw.extension,aiType:n.data.raw.aiType,uploadDate:n.data.raw.uploadDate,urls:n.data.raw.urls}}async getImageWithAtMessage(e,t){if(!t.pid)return j(e,`请提供作品 ID (PID)`);try{return A(await this.getImageWithBuffer(t.pid,t.page),this.config)}catch(t){return this.ctx.logger.error(t),j(e,(t instanceof Error?t.message:String(t))||`获取图片失败`)}}async getAllImagesWithAtMessage(e,t){if(!t.pid)return j(e,`请提供作品 ID (PID)`);try{let n=await this.getIllustDetail(this.ctx,t.pid);if(n.error||!n.body)return j(e,`无法获取插画详情`);let r=n.body.pageCount||1;if(r===1)return A(await this.getImageWithBuffer(t.pid,0),this.config);let i=[];for(let e=0;e<r;e++){await M(this.config,e);let n=await this.getImageWithBuffer(t.pid,e);i.push(n)}return ee(i,this.config)}catch(t){return this.ctx.logger.error(t),j(e,(t instanceof Error?t.message:String(t))||`获取图片失败`)}}};S(`pdiscovery`,L),S(`pfollowing`,R),S(`safebooru`,class extends T{static description=`通过 Safebooru API 获取图片`;endpoint=`https://safebooru.org/index.php`;async getMetaData({context:e},t){try{let n=``;t.tag&&(n=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let r={page:`dapi`,s:`post`,q:`index`,json:`1`,limit:`1`,tags:`${n} sort:random`},i=`${this.endpoint}?${new URLSearchParams(r).toString()}`,a=await e.http.get(i,{proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!Array.isArray(a)||a.length===0)return{status:`error`,data:Error(`No image data returned`)};let o=a[0],s=`https://safebooru.org/images/${o.directory}/${o.image}?${o.id}`,c=o.sample?`https://safebooru.org/samples/${o.directory}/sample_${o.image}?${o.id}`:s,l={id:o.id,title:`Safebooru - ${o.id}`,author:o.owner.replace(/_/g,` `),r18:![`safe`,`general`].includes(o.rating),tags:o.tags.split(` `),extension:o.image.split(`.`).pop(),aiType:0,uploadDate:new Date(o.created_at).getTime(),urls:{original:s,regular:c}};return $.debug(`成功获取图片元数据`,{metadata:l}),{status:`success`,data:{url:this.config.imageProcessing.compress?c:s,urls:{regular:c,original:s},raw:l}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://safebooru.org`}}setConfig(e){this.config=e}}),S(`sankaku`,class extends T{static description=`通过 Sankaku Complex API 获取图片`;endpoint=`https://capi-v2.sankakucomplex.com`;http;constructor(e,t){super(e,t),this.http=e.http.extend({headers:{"User-Agent":V},proxyAgent:t.isProxy?t.proxyHost:void 0})}get keyPair(){let e=this.config.sankaku?.keyPairs||[];return e.length?e[Math.floor(Math.random()*e.length)]:null}async login(e){if(!e.accessToken){let t=await this.http.post(`${this.endpoint}/auth/token`,{login:e.login,password:e.password},{proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});t.access_token&&(e.accessToken=t.access_token,e.tokenType=t.token_type)}return e}async getMetaData(e,t){try{let e=this.keyPair;if(!e)throw Error(`No API credentials provided`);await this.login(e);let n=``;t.tag&&(n=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let r=new URLSearchParams({tags:`${n} order:random${this.config.isR18&&t.r18?``:` rating:safe`}`,limit:`1`}),i=await this.http.get(`${this.endpoint}/posts/random`,{params:r,headers:{Authorization:`${e.tokenType} ${e.accessToken}`},proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!i.length)return{status:`error`,data:Error(`No image data returned`)};let a=i[0],o={id:a.id,title:a.source||`Sankaku - ${a.id}`,author:a.author.name.replace(/_/g,` `),r18:[`explicit`,`questionable`].includes(a.rating),tags:a.tags.map(e=>e.name),extension:a.file_url.split(`.`).pop(),uploadDate:new Date(a.created_at).getTime(),aiType:0,urls:{original:a.file_url,regular:a.sample_url}};return $.debug(`成功获取图片元数据`,{metadata:o}),{status:`success`,data:{url:this.config.imageProcessing.compress?a.sample_url:a.file_url,urls:{regular:a.sample_url,original:a.file_url},raw:o}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://sankaku.app`}}setConfig(e){this.config=e}}),S(`yande`,class extends T{static description=`通过 Yande.re API 获取图片`;endpoint=`https://yande.re`;keyPairs=[];hashPassword(e){let t=`choujin-steiner--${e}--`,n=i(`sha1`);return n.update(t),n.digest(`hex`)}setConfig(e){this.config=e,e.yande?.keyPairs?.length&&(this.keyPairs=e.yande.keyPairs)}get keyPair(){if(!this.keyPairs.length)return null;let e=this.keyPairs[Math.floor(Math.random()*this.keyPairs.length)];return{login:e.login,password_hash:this.hashPassword(e.password)}}async getMetaData({context:e},t){try{let n=this.keyPair,r=``;t.tag&&(r=t.tag.split(/[,,]/).map(e=>e.trim()).filter(Boolean).join(` `));let i={tags:`${r} order:random`,limit:1,...n?{login:n.login,password_hash:n.password_hash}:{}};this.config.isR18&&t.r18?i.tags+=` rating:explicit`:i.tags+=` rating:safe`;let a=await e.http.get(`${this.endpoint}/post.json`,{params:i,proxyAgent:this.config.isProxy?this.config.proxyHost:void 0});if(!Array.isArray(a)||a.length===0)return{status:`error`,data:Error(`No image data returned`)};let o=a[0],s=this.config.imageProcessing.compress?o.sample_url:o.file_url,c={id:o.id,title:``,author:o.author.replace(/_/g,` `),r18:o.rating===`e`||o.rating===`q`,tags:o.tags.split(` `),extension:o.file_url.split(`.`).pop(),aiType:0,uploadDate:new Date(o.created_at).getTime(),urls:{original:o.file_url,regular:o.sample_url}};return $.debug(`成功获取图片元数据`,{metadata:c}),{status:`success`,data:{url:s,urls:{regular:o.sample_url,original:o.file_url},raw:c}}}catch(e){return{status:`error`,data:e}}}getMeta(){return{referer:`https://yande.re`}}});function B(e,t,n){if(n){let r=C(n);if(r)return new r(e,t);throw Error(`未找到提供程序:${n}`)}if(!t.defaultSourceProvider?.length)throw Error(`未配置任何图片来源`);let r=y(t.defaultSourceProvider)[0],i=C(r);if(i)return new i(e,t);throw Error(`未找到提供程序:${r}`)}const V=`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36`;async function H(e,t,n,r){return d(e,`fetchImage`,async()=>{let i={"User-Agent":V};r?.getMeta?.()?.referer&&(i.Referer=r.getMeta().referer);let a=await e.http.get(n,{responseType:`arraybuffer`,proxyAgent:t.isProxy?t.proxyHost:void 0,headers:i}),o=await f(Buffer.from(a))||`image/png`;return $.debug(`检测到 MIME 类型`,{mimeType:o}),[a,o]})}async function U(e,t,n,r){if(!B(e,n,r))throw Error(`未选择有效的图片来源,请检查配置`);let i=await B(e,n,r).getMetaData({context:e},{r18:n.isR18&&Math.random()<n.r18P,excludeAI:n.excludeAI,tag:t||void 0,proxy:n.baseUrl?n.baseUrl:void 0});if(i.status===`error`)return null;let[a,o]=await H(e,n,i.data.url,B(e,n,r)),s=!!i.data.urls?.regular,c=!!n.imageProcessing.isFlip,l=!!n.imageProcessing.confusion,u=!!n.imageProcessing.compress&&!s,p=a.byteLength>=32*1024*1024;if(!p&&(c||l||u)){let t=await d(e,`processImage`,async()=>await v(e,Buffer.from(a),n,s)),r=await f(t)||`image/png`;return{...i.data.raw,data:t,mimeType:r,raw:i.data.raw}}else{p&&(c||l||u)&&$.warn(`图片过大,已跳过处理并原样发送`,{sizeMB:Math.round(a.byteLength/1024/1024*10)/10});let e=Buffer.from(a);return{...i.data.raw,data:e,mimeType:o,raw:i.data.raw}}}async function W(e,t,r,i){try{let a=await U(e,r,t,i);return a?A(a,t):n(`message`,[n(`text`,{content:`没有获取到喵 `})])}catch(t){return e.logger.error(t),n(`message`,[n(`text`,{content:`图片获取失败了喵~,${t}`})])}}async function G(e,t,n,r){let i=new z(e,t);return r.all?i.getAllImagesWithAtMessage(n,r):i.getImageWithAtMessage(n,r)}function K(e,t){e.command(`pixluna.get`,`直接通过图源获取图片`),e.command(`pixluna.get.pixiv <pid:string>`,`通过 pid 获取图片`).option(`pages`,`-p <pages:number>`,{fallback:0}).option(`all`,`-a`).action(async({session:n,options:r},i)=>await G(e,t,n.userId,{pid:i,page:r.pages,all:r.all}))}function q(e,t){e.command(`pixluna.source`,`查看图源`).action(async({session:e})=>{let t=w(),r=n(`message`,[n(`text`,{content:`可用的图片来源: `}),...t.map(e=>n(`text`,{content:`- ${e}: ${C(e)?.description||``}\n`}))]);await e.send(r)})}function J(e,t){K(e,t),q(e,t)}async function Y(e,t,n,r){try{await t.deleteMessage(n,r)}catch(t){e.logger(`recall`).warn(`撤回消息时发生错误`,{channelId:n,messageId:r,error:t})}}async function X(e,t,n,r=6e4){n?.length&&(e.logger(`recall`).debug(`设置消息自动撤回`,{channelId:t.channelId,messageIds:n,timeout:r}),setTimeout(async()=>{for(let r of n)await Y(e,t.bot,t.channelId,r)},r))}const Z=t.intersect([t.object({isR18:t.boolean().default(!1).description(`是否允许返回 R18 内容`),messageBefore:t.string().default(`不可以涩涩哦~`).description(`触发响应时的消息,留空则不发送`),showTags:t.boolean().default(!0).description(`是否显示图片标签`),excludeAI:t.boolean().default(!1).description(`是否排除 AI 生成作品`),maxConcurrency:t.number().default(1).description(`最大并发请求数`).min(1).max(10).step(1),forwardMessage:t.boolean().default(!0).description(`是否以转发消息格式发送图片`),autoRecall:t.object({enable:t.boolean().default(!1).description(`是否启用自动撤回`),delay:t.number().default(30).description(`自动撤回延迟时间(秒)`).min(1).max(120).step(1)}),apiDelay:t.number().default(1600).description(`API请求和循环的延迟时间(毫秒)`).min(0).max(1e4).step(100)}).description(`通用设置`),t.object({imageProcessing:t.object({confusion:t.boolean().default(!1).description(`是否启用图片混淆处理(对某些平台有奇效)`),compress:t.boolean().default(!1).description(`是否压缩图片(能大幅度提升发送的速度,但是对图片质量有影响)`),compressionLevel:t.number().default(6).description(`压缩等级(0-9,数值越大压缩越强)`).min(0).max(9).step(1),isFlip:t.boolean().default(!1).description(`是否启用图片翻转处理`),flipMode:t.union([t.const(`horizontal`).description(`水平翻转`),t.const(`vertical`).description(`垂直翻转`),t.const(`both`).description(`水平和垂直翻转`)]).default(`horizontal`).description(`图片翻转模式`)}).description(`图片处理设置`)}),t.object({r18P:t.percent().default(.1).description(`R18 内容出现的概率(仅当 isR18 为 true 时生效)`).min(0).max(1).step(.01)}).description(`R18 内容设置`),t.object({isProxy:t.boolean().default(!1).description(`是否使用代理`),proxyHost:t.string().default(`http://127.0.0.1:7890`).description(`代理服务器地址`),baseUrl:t.string().default(`i.pixiv.re`).description(`图片反代服务的地址`)}).description(`代理设置`),t.object({defaultSourceProvider:t.array(t.union([t.const(`danbooru`).description(`Danbooru API`),t.const(`e621`).description(`E621 API`),t.const(`gelbooru`).description(`Gelbooru API`),t.const(`konachan`).description(`Konachan API`),t.const(`lolibooru`).description(`Lolibooru API`),t.const(`lolicon`).description(`Lolicon API`),t.const(`lolisuki`).description(`Lolisuki API`),t.const(`pdiscovery`).description(`Pixiv Discovery`),t.const(`pfollowing`).description(`Pixiv Following`),t.const(`safebooru`).description(`Safebooru API`),t.const(`sankaku`).description(`Sankaku API`),t.const(`yande`).description(`Yande.re API`)])).description(`选择默认图片来源(可多选)`).default([`lolicon`]).role(`select`)}).description(`图源设置`),t.object({pixiv:t.object({phpSESSID:t.string().description(`Pixiv 的 PHPSESSID,用于访问个性化内容返回的图片分级取决于该 Pixiv 账号所有者的分级设置`).role(`secret`).default(``),userId:t.string().description(`Pixiv 用户 ID,用于获取关注列表`).default(``)}).description(`Pixiv 设置`)}),t.object({danbooru:t.object({keyPairs:t.array(t.object({login:t.string().required().description(`Danbooru 用户名`),apiKey:t.string().required().role(`secret`).description(`Danbooru API Key`)})).default([]).description(`Danbooru API 鉴权信息`)}).description(`Danbooru 设置`)}),t.object({e621:t.object({keyPairs:t.array(t.object({login:t.string().required().description(`E621 用户名`),apiKey:t.string().required().role(`secret`).description(`E621 API Key`)})).default([]).description(`E621 API 鉴权信息`)}).description(`E621 设置`)}),t.object({gelbooru:t.object({keyPairs:t.array(t.object({apiKey:t.string().required().role(`secret`).description(`Gelbooru API Key`)})).default([]).description(`Gelbooru API 鉴权信息`)}).description(`Gelbooru 设置`)}),t.object({lolibooru:t.object({keyPairs:t.array(t.object({login:t.string().required().description(`Lolibooru 用户名`),password:t.string().required().role(`secret`).description(`Lolibooru 密码`)})).default([]).description(`Lolibooru API 鉴权信息`)}).description(`Lolibooru 设置`)}),t.object({sankaku:t.object({keyPairs:t.array(t.object({login:t.string().required().description(`Sankaku Complex 用户名`),password:t.string().required().role(`secret`).description(`Sankaku Complex 密码`),tokenType:t.string().hidden().default(`Bearer`),accessToken:t.string().hidden()})).default([]).description(`Sankaku Complex API 鉴权信息`)}).description(`Sankaku Complex 设置`),konachan:t.object({keyPairs:t.array(t.object({login:t.string().required().description(`Konachan 用户名`),password:t.string().required().role(`secret`).description(`Konachan 密码`)})).default([]).description(`Konachan API 鉴权信息`)}).description(`Konachan 设置`),yande:t.object({keyPairs:t.array(t.object({login:t.string().required().description(`Yande.re 用户名`),password:t.string().required().role(`secret`).description(`Yande.re 密码`)})).default([]).description(`Yande.re API 鉴权信息`)}).description(`Yande.re 设置`)}),t.object({isLog:t.boolean().default(!1).description(`是否输出debug日志`)}).description(`日志设置`)]),Q=`pixluna`;let $;async function te(e,t=0,n=!0){(!n||t>0)&&await new Promise(t=>setTimeout(t,e.apiDelay))}function ne(e,t){$=c(e),re(t),e.command(`pixluna`,`来张色图`).alias(`色图`).option(`number`,`-n <value:number>`,{fallback:1}).option(`source`,`-s <source:string>`,{fallback:``}).option(`tag`,`-t <tags:string>`,{fallback:``}).action(async({session:r,options:i})=>{if(!Number.isInteger(i.number)||i.number<=0)return j(r.userId,`图片数量必须是大于 0 的整数哦~`);t.messageBefore&&await r.send(t.messageBefore);let a=Array.isArray(t.defaultSourceProvider)?t.defaultSourceProvider:[t.defaultSourceProvider],o={...t,defaultSourceProvider:i.source?[i.source]:a};if(i.source)try{B(e,{...o,defaultSourceProvider:[i.source]})}catch(e){return j(r.userId,e.message)}let s=[],c=new u(t.maxConcurrency);for(let t=0;t<Math.min(10,i.number);t++)await te(o,t),c.add(d(e,`${t+1} image`,async()=>{let t=await W(e,o,i.tag,i.source);s.push(t)}));await c.run();let l=[];try{let i=await d(e,`send message`,()=>{let e=n(`message`,s);return t.forwardMessage?r.send(n(`message`,{forward:t.forwardMessage},s)):r.send(e)});l=Array.isArray(i)?i:[i]}catch(e){$.error(`发送消息时发生错误`,{error:e});let t=await r.send(j(r.userId,`消息发送失败了喵,账号可能被风控 `));t&&(l=l.concat(Array.isArray(t)?t:[t]))}l.length>0&&t.autoRecall.enable&&await X(e,r,l,t.autoRecall.delay*1e3)}),J(e,t)}function re(t){t.isLog&&l(e.DEBUG)}export{Z as Config,ne as apply,$ as logger,Q as name};