-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
10 lines (10 loc) · 6.38 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
"use strict";var y=Object.defineProperty;var E=(n,e,t)=>e in n?y(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var m=(n,e,t)=>E(n,typeof e!="symbol"?e+"":e,t);const{Plugin}=require("siyuan");class SiyuanPlugin extends Plugin{constructor(){super(...arguments);m(this,"onunloadFn",[])}addUnloadFn(t){this.onunloadFn.push(t)}onunload(){this.onunloadFn.forEach(t=>t())}}let taskID=[];function scheduleCronJob(n,e){n=n.replace(/[\u200B-\u200D\uFEFF]/g,"");const t=n.split(" ");if(t.length<5)throw new Error("Invalid Cron expression");const[o,a,s,c,r]=t;function i(){const d=new Date,f=d.getMinutes().toString(),h=d.getHours().toString(),p=d.getDate().toString(),g=(d.getMonth()+1).toString(),k=(d.getDay()+1).toString();l(o,f)&&l(a,h)&&l(s,p)&&l(c,g)&&l(r,k)&&e()}function l(d,f){return d==="*"||d.includes(f)}const u=setInterval(i,6e4);taskID.push(u)}function removeAllCronJob(){console.log(`移除所有定时任务,数量:${taskID.length}`),taskID.forEach(n=>clearInterval(n)),taskID=[]}const MAX_FEED_NUM=100,SUMMARY_LENGTH=150,DEFAULT_CRON="1 * * * *",FETCH_TIMEOUT=1e4,{fetchSyncPost}=require("siyuan");function insertBlock(n){return fetchSyncPost("/api/block/insertBlock",n)}function sqlQuery(n){return fetchSyncPost("/api/query/sql",{stmt:n})}function get_av_map(n){return fetchSyncPost("/api/av/getAttributeViewKeys",{id:n}).then(e=>e.data).then(e=>e.map(t=>t.keyValues.map(o=>{var a,s;return{key:o.key.name,value:(s=(a=o.values.find(c=>{var r;return(r=c.text)==null?void 0:r.content}))==null?void 0:a.text)==null?void 0:s.content,avName:t.avName}})).flat().reduce((t,o)=>(t[o.key]=(o.avName.includes("feed")?o.value:t[o.key])??o.value??"",t),{}))}const{fetchPost:fetchPost$1}=require("siyuan");async function parseFeed(feedDoc){var n;let timeout=Number(feedDoc.getAttr("timeout"));timeout=timeout>=3e3?timeout:FETCH_TIMEOUT;const url=(n=feedDoc.getAttr("feed"))==null?void 0:n.trim(),resText=await new Promise((e,t)=>{fetchPost$1("/api/network/forwardProxy",{url,method:"GET",timeout,contentType:"application/xml",headers:[],payload:{},payloadEncoding:"text",responseEncoding:"text"},o=>{o.code!==0&&o.data.status!==200?t(new Error(o.msg)):e(o.data.body)})}),customCode=feedDoc.getAttr("customParse");if(customCode){const customParseFun=eval(customCode),res=await customParseFun(feedDoc,resText,{xssDefend,elText});return res}const parser=new DOMParser,dom=parser.parseFromString(resText,"text/xml");return dom.querySelector("feed")?{title:elText(dom,"feed > title"),subtitle:elText(dom,"feed > subtitle"),updated:elText(dom,"feed > updated"),entryList:Array.from(dom.querySelectorAll("feed > entry")).map(e=>{var t;return{title:elText(e,"title"),published:elText(e,"published"),updated:elText(e,"updated"),summary:elText(e,"summary")||elText(e,"content"),link:xssDefend((t=e.querySelector("link"))==null?void 0:t.getAttribute("href"))}})}:dom.querySelector("channel")?{title:elText(dom,"channel > title"),subtitle:elText(dom,"channel > description"),updated:elText(dom,"channel > lastBuildDate"),entryList:Array.from(dom.querySelectorAll("channel > item")).map(e=>({title:elText(e,"title"),published:elText(e,"pubDate"),updated:elText(e,"updated"),summary:elText(e,"description"),link:elText(e,"link")}))}:(console.log("rss解析失败",feedDoc,url),new Error(`未知的格式,可以将此消息发送给开发者 [email protected] (feed_siyuan_plugin):${url}`))}async function parseFeedBlock(n){var a;const e={attr:{},entryBlock:[],av_attr:{},getAttr(s){var c;return((c=this.attr[s])==null?void 0:c.value)??this.av_attr[s]}},t=(a=(await sqlQuery(`SELECT * FROM blocks WHERE parent_id="${n}" and fcontent LIKE 'feed:%' limit 1`)).data)==null?void 0:a[0];if(t){e.attrBlock=t;const s=(await sqlQuery(`SELECT * FROM blocks WHERE parent_id="${t==null?void 0:t.id}" limit 20`)).data;Object.assign(e.attr,o(s))}return e.entryBlock=(await sqlQuery(`SELECT * FROM blocks
WHERE
parent_id="${n}" AND (markdown LIKE "* [ ] #%" OR markdown LIKE "* [X] #%")
ORDER BY created DESC
LIMIT ${MAX_FEED_NUM*3}`)).data,Object.assign(e.av_attr,await get_av_map(n)),e;function o(s){const c=s.map(i=>[Array.from(i.content.trim().match(/(.*?):([\s\S]+)/)??[]),i]).filter(i=>i[0].length===3),r={};for(const[[i,l,u],d]of c){let f=u;l==="feed"&&(f=u.replace("\\_","_")),r[l]={value:f,block:d}}return r}}async function getAllFeedBlocks(){return(await sqlQuery('SELECT * FROM attributes WHERE name="bookmark" and value="feed"')).data}function elText(n,e){var t;return xssDefend((t=n.querySelector(e))==null?void 0:t.textContent)}function xssDefend(n){if(!n)return"";let e=(new DOMParser().parseFromString(n,"text/html").documentElement.textContent??"").replace(/[<>\[\]\n]/g,"");return e.length>SUMMARY_LENGTH&&(e=e.substring(0,SUMMARY_LENGTH)+"..."),e}function linkFilter(n){return(n||"").replace(/#.*$/g,"")}const{fetchPost}=require("siyuan");class FeedPlugin extends SiyuanPlugin{constructor(){super(...arguments);m(this,"_feedFetch",[])}async onload(){this.addCommand({hotkey:"",langKey:"_feedFetch",langText:"立刻对所有feed进行一次拉取",callback:async()=>{await this.registerAllFeed(),this._feedFetch.forEach(t=>t())}}),this.registerAllFeed()}async registerAllFeed(){this._feedFetch=[],removeAllCronJob();const t=await getAllFeedBlocks();return Promise.all(t.map(async o=>{const a=await parseFeedBlock(o.block_id);if(a.getAttr("feed")){const s=a.getAttr("cron")??DEFAULT_CRON;console.log(`注册 cron job 表达式:${s} by ${a.getAttr("feed")}`,a);const c=async()=>{this.feedFetch(o.block_id)};scheduleCronJob(s,c),this._feedFetch.push(c)}else console.log(a,"没有读取到 feed 属性,请对照文档进行设定 feed")}))}async feedFetch(t){const o=await parseFeedBlock(t),a=await parseFeed(o);if(a instanceof Error)throw a;const s=a.entryList.sort((r,i)=>Number(i.updated)-Number(r.updated)).filter(r=>r.link).filter(r=>!o.entryBlock.find(l=>r.link&&l.content.split(`
`)[0].includes(linkFilter(r.link)))),c=`feed:${o.getAttr("feed")} 共 ${a.entryList.length} 条,新增 ${s.length} 条`;console.log(c),fetchPost("/api/notification/pushMsg",{msg:c}),s.forEach(async r=>{var u;console.log("insertBlock ",r);const i=((u=o.attrBlock)==null?void 0:u.id)??t;let l=`* [ ] ###### [${r.title??r.link}](${r.link})
`;r.published&&(l+=` - published:${r.published}
`),r.updated&&(l+=` - updated:${r.updated}
`),r.summary&&(l+=` > ${r.summary}
`),l+=" ",insertBlock({dataType:"markdown",previousID:i,data:l})})}async onunload(){removeAllCronJob(),this.commands=[]}}module.exports=FeedPlugin;