// ==UserScript== // @name 链滴新消息提示 // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.1.2 // @description 链滴新消息提示 // @author Wilsons // @icon https://ld246.com/images/favicon.png // @background // @connect ld246.com // @grant GM_xmlhttpRequest // @grant GM_notification // @grant GM_getValue // @grant GM_setValue // @grant GM_info // @grant GM_log // ==/UserScript== /* ==UserConfig== noticeConfig: delayTime: title: 检查消息时间间隔 description: 多久获取一次消息(单位分钟) type: number default: 10 min: 1 max: 240 password: false unit: 分钟 enableNewDoc: title: 是否开启新帖子提示 description: 开启 type: checkbox default: true enableNewNotice: title: 是否开启新消息提示 description: 开启 type: checkbox default: true token: title: 链滴Token description: 在链滴 设置 - 账号 中找到 API Token type: text default: min: 3 max: 50 password: false ==/UserConfig== */ /////////////////// 主流程 //////////////////////////// let token = ''; const main = async () => { let hasNewDoc=false, hasNewNotice=false, lastArticleId; const isFirstRun = getUnixTimestamp() > GM_getValue('firstRunEndTime', 0); if(isFirstRun) GM_setValue('firstRunEndTime', getTodayEndTimestamp()); const lastRunTime = GM_getValue('lastRunTime') || 0; const delayTime = GM_getValue('noticeConfig.delayTime') || 0; if(!isFirstRun && getUnixTimestamp() - lastRunTime < delayTime * 60) return; GM_setValue('lastRunTime', getUnixTimestamp()); token = GM_getValue('noticeConfig.token'); if(!token) { if(isFirstRun) shownNotification('请先配置Token,方法:在链滴 设置 - 账号 中找到 API Token', ()=>{ window.open('https://ld246.com/settings/account'); }); return; } lastArticleId = GM_getValue('lastArticleId'); if(!lastArticleId) { lastArticleId = await getLastArticleId(); GM_setValue('lastArticleId', lastArticleId); } const enableNewDoc = GM_getValue('noticeConfig.enableNewDoc'); if(enableNewDoc) { const aid = await getLastArticleId(); if(aid !== lastArticleId) { hasNewDoc = true; GM_setValue('lastArticleId', aid); } } const enableNewNotice = GM_getValue('noticeConfig.enableNewNotice'); if(enableNewNotice) { const num = await getNoticeNums(); if(num) hasNewNotice = true; } if(hasNewDoc && hasNewNotice) { shownNotification('有新帖发布和有新消息!', ()=>{ window.open('https://ld246.com/notifications/commented'); }); } else if(hasNewDoc) { shownNotification('有新帖发布!', ()=>{ window.open('https://ld246.com/'); }); } else if(hasNewNotice) { shownNotification('您有新的消息', ()=>{ window.open('https://ld246.com/notifications/commented'); }); } }; // 启动主函数 main(); setInterval(()=>{ main(); }, 60000); /////////////////// 辅助函数 //////////////////////////// async function getLastArticleId() { try{ // see https://ld246.com/article/1488603534762 const result = await fetchUrl('https://ld246.com/api/v2/articles/latest?p=1'); const json = JSON.parse(result.text); const aid = json?.data?.articles[0]?.oId; return aid; }catch(e) { console.log(e); GM_log(`《${GM_info.script.name}》脚本异常:${e}`, "warn"); return 0; } } async function getNoticeNums() { try{ // see https://ld246.com/article/1488603534762 const result = await fetchUrl('https://ld246.com/api/v2/notifications/unread/count'); const json = JSON.parse(result.text); const nums = Object.values(json?.data) || []; const sum = nums.reduce((acc, curr) => acc + curr, 0); return sum; }catch(e) { console.log(e); GM_log(`《${GM_info.script.name}》脚本异常:${e}`, "warn"); return 0; } } function shownNotification(msg, callback) { GM_notification({ title: `《${GM_info.script.name}》脚本提示`, text: `${msg}`, requireInteraction: true, onclick: callback }); } function fetchUrl(url, method = 'GET', data = null) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: method, url: url, data: data, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `token ${token}`, }, onload: (response) => { if (response.status >= 200 && response.status < 400) { resolve({text: response.responseText, status: response.status}); } else { reject(new Error(`网络请求状态码异常-${response.status}`)); } }, onerror: (error) => { reject(new Error(`网络请求异常-${error}`)); } }); }); } function getUnixTimestamp() { return Math.floor(Date.now() / 1000); } function getTodayEndTimestamp() { const end = new Date(); end.setHours(23, 59, 59, 999); // 设置为今天 23:59:59.999 return Math.floor(end.getTime() / 1000); }