From 6dfee7efb8397033dafab5b78d6fdd85d9478661 Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 25 Nov 2023 10:20:13 +0800 Subject: [PATCH 01/74] =?UTF-8?q?fix:=20=E5=87=BA=E7=8E=B0=E5=B8=90?= =?UTF-8?q?=E5=8F=B7=E6=9C=AA=E7=99=BB=E5=BD=95=E9=94=99=E8=AF=AF=E6=97=B6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=B7=B3=E8=BD=AC=E4=B8=8B=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=B8=90=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/monitor.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 90584c3bf3..9cd96c53a1 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -56,6 +56,9 @@ class Monitor extends Searcher { case 1001: event_bus.emit('Turn_off_the_Monitor', '评论失败') break; + case 1010: + event_bus.emit('Turn_off_the_Monitor', '已掉号') + break; case 1004: event_bus.emit('Turn_off_the_Monitor', '需要输入验证码') break @@ -194,7 +197,6 @@ class Monitor extends Searcher { case 1007: case 1008: case 1009: - case 1010: case 1011: case 2002: case 2003: @@ -217,6 +219,7 @@ class Monitor extends Searcher { is_outof_maxfollow = 2005 break; case 1001: + case 1010: case 1004: case 2001: case 3001: From 0c610701cb1e1cf8615b5233a2c14239a6517b74 Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 25 Nov 2023 10:42:17 +0800 Subject: [PATCH 02/74] =?UTF-8?q?fix:=20=E8=AF=84=E8=AE=BA=E5=B9=B6?= =?UTF-8?q?=E8=BD=AC=E5=8F=91=20(#259)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #259 --- lib/core/monitor.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 9cd96c53a1..9ee722f9a6 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -603,7 +603,7 @@ class Monitor extends Searcher { [4], () => bili.sendChatWithOcr( rid, - is_repost_then_chat ? relay_chat.split('//')[0] : chat, + chat, chat_type ) ) @@ -671,7 +671,10 @@ class Monitor extends Searcher { status = await retryfn( 5, [3, 4], - () => bili.autoRelay(global_var.get("myUID"), dyid, relay_chat, ctrl) + () => bili.autoRelay( + global_var.get("myUID"), dyid, + is_repost_then_chat ? chat + relay_chat : relay_chat + , ctrl) ) if (status) { From 5d30178bd37947832716b90827a8dc8add7f0655 Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 25 Nov 2023 11:21:31 +0800 Subject: [PATCH 03/74] =?UTF-8?q?ci:=20docker=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8618b89f1b..56525898a4 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -31,4 +31,4 @@ jobs: with: push: true tags: ${{ secrets.DOCKERHUB_REPO }} - platforms: "linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x" + platforms: "linux/amd64,linux/arm64" From f3af8dff17d5f1d2387528f663adccc9fb4e6a2d Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 25 Nov 2023 13:46:42 +0800 Subject: [PATCH 04/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c9e1835ad..ff8d874bd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## 主要变化(2.8.12) +* 5d30178 ci: docker构建 +* 0c61070 fix: 评论并转发 (#259) +* 6dfee7e fix: 出现帐号未登录错误时自动跳转下一个帐号 + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.11) * 6496a8f fix: fs.close diff --git a/package.json b/package.json index e31ff2a94b..070554aa0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.11", + "version": "2.8.12", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From b86e756520369e239b4e58c6b83cd56a811fd105 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 1 Dec 2023 10:16:11 +0800 Subject: [PATCH 05/74] =?UTF-8?q?fix:=20at=E9=94=99=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/monitor.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 9ee722f9a6..2b0296f4a5 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -596,6 +596,10 @@ class Monitor extends Searcher { .replace( new RegExp(copy_chat[0], 'g'), global_var.get("myUNAME") || '') + } else { + if (is_repost_then_chat) { + chat = chat + relay_chat + } } status = await retryfn( @@ -672,9 +676,10 @@ class Monitor extends Searcher { 5, [3, 4], () => bili.autoRelay( - global_var.get("myUID"), dyid, - is_repost_then_chat ? chat + relay_chat : relay_chat - , ctrl) + global_var.get("myUID"), + dyid, + relay_chat, + ctrl) ) if (status) { From addb9c65feb35c5ccb072bb660ae1755a2f17023 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 1 Dec 2023 10:21:08 +0800 Subject: [PATCH 06/74] fix: ghproxy.com->mirror.ghproxy.com (#333) Fixed #333 --- lib/update.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/update.js b/lib/update.js index 72bd93dee3..65364629df 100644 --- a/lib/update.js +++ b/lib/update.js @@ -68,7 +68,7 @@ async function update(isDdownload) { if (download_url.length) { if (isDdownload) { await try_for_each(download_url.entries(), async ([i, url]) => { - let proxy_url = "https://ghproxy.com/"; + let proxy_url = "https://mirror.ghproxy.com/"; proxy_url += url log.warn('自动下载', `切换代理${proxy_url}`) await download(proxy_url, `latest_version${i}.zip`) From 92fab1774d4c687ed9000cd81d2792a4fbb16fb1 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 1 Dec 2023 10:22:40 +0800 Subject: [PATCH 07/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff8d874bd6..03877f7c4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 主要变化(2.8.13) +* addb9c6 fix: ghproxy.com->mirror.ghproxy.com (#333) +* b86e756 fix: at错位 + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.12) * 5d30178 ci: docker构建 * 0c61070 fix: 评论并转发 (#259) diff --git a/package.json b/package.json index 070554aa0e..5adffc32ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.12", + "version": "2.8.13", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 780a3a9840710182494f3ab6b22b168f18d72103 Mon Sep 17 00:00:00 2001 From: shanmite Date: Wed, 6 Mar 2024 19:36:18 +0800 Subject: [PATCH 08/74] fix: update get_dynamic_detail api (#350) * Update api.bili.js * Update bili.js * Update bili.js --- lib/net/api.bili.js | 9 +++++---- lib/net/bili.js | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index 59b1269da8..585c288615 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -5,12 +5,13 @@ module.exports = Object.freeze({ DYNAMIC_REPOST_SHARE: 'https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/share', DYNAMIC_SVR_CREATE_DRAW: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create_draw', DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V2: 'https://api.vc.bilibili.com/dynamic_svr/v2/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V3: 'https://api.vc.bilibili.com/dynamic_svr/v3/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V4: 'https://api.vc.bilibili.com/dynamic_svr/v4/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V5: 'https://api.vc.bilibili.com/dynamic_svr/v5/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V6: 'https://api.vc.bilibili.com/dynamic_svr/v6/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V7: 'https://api.vc.bilibili.com/dynamic_svr/v7/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V9: 'https://api.vc.bilibili.com/dynamic_svr/v9/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11: 'https://api.vc.bilibili.com/dynamic_svr/v11/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13: 'https://api.vc.bilibili.com/dynamic_svr/v13/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', @@ -43,4 +44,4 @@ module.exports = Object.freeze({ WEB_INTERFACE_CARD: 'https://api.bilibili.com/x/web-interface/card', WEB_INTERFACE_NAV_STAT: "https://api.bilibili.com/x/web-interface/nav/stat", WEB_INTERFACE_SEARCH_TYPE: 'https://api.bilibili.com/x/web-interface/search/type', -}) \ No newline at end of file +}) diff --git a/lib/net/bili.js b/lib/net/bili.js index 3982c57a58..c96e83418c 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -414,7 +414,7 @@ const bili_client = { }, _getOneDynamicByDyid: new Line('获取一个动态的细节', [ (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V2, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1, config: { retry: false }, query: { dynamic_id @@ -428,28 +428,35 @@ const bili_client = { } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V4, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V5, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V5, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V7, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V6, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V9, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V7, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11, + config: { retry: false }, + query: { + dynamic_id + } + }), + (dynamic_id) => get({ + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13, config: { retry: false }, query: { dynamic_id From cb6fad05e43427b4f0f4aa899fb5eba7739dfaa3 Mon Sep 17 00:00:00 2001 From: ypw96 <90349951+ypw96@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:30:34 +0800 Subject: [PATCH 09/74] fix: get_dynamic_detail api (#351) * Update api.bili.js * Update api.bili.js * Update bili.js --- lib/net/api.bili.js | 10 +++++----- lib/net/bili.js | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index 585c288615..cc23fef3e2 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -5,13 +5,13 @@ module.exports = Object.freeze({ DYNAMIC_REPOST_SHARE: 'https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/share', DYNAMIC_SVR_CREATE_DRAW: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create_draw', DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V3: 'https://api.vc.bilibili.com/dynamic_svr/v3/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V5: 'https://api.vc.bilibili.com/dynamic_svr/v5/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V7: 'https://api.vc.bilibili.com/dynamic_svr/v7/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V9: 'https://api.vc.bilibili.com/dynamic_svr/v9/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10: 'https://api.vc.bilibili.com/dynamic_svr/v10/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11: 'https://api.vc.bilibili.com/dynamic_svr/v11/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V12: 'https://api.vc.bilibili.com/dynamic_svr/v12/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13: 'https://api.vc.bilibili.com/dynamic_svr/v13/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V14: 'https://api.vc.bilibili.com/dynamic_svr/v14/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V15: 'https://api.vc.bilibili.com/dynamic_svr/v15/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V16: 'https://api.vc.bilibili.com/dynamic_svr/v16/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', diff --git a/lib/net/bili.js b/lib/net/bili.js index c96e83418c..b692d39951 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -414,49 +414,49 @@ const bili_client = { }, _getOneDynamicByDyid: new Line('获取一个动态的细节', [ (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V3, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V5, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V12, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V7, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V9, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V14, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V15, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V16, config: { retry: false }, query: { dynamic_id From f5bdd289d506fbf535fab96f05ad18516866434c Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 9 Mar 2024 15:13:15 +0800 Subject: [PATCH 10/74] fix: update api getOneDynamicByDyid --- lib/net/api.bili.js | 13 +++++++------ lib/net/bili.js | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index cc23fef3e2..61a91f3d98 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -5,13 +5,14 @@ module.exports = Object.freeze({ DYNAMIC_REPOST_SHARE: 'https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/share', DYNAMIC_SVR_CREATE_DRAW: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create_draw', DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10: 'https://api.vc.bilibili.com/dynamic_svr/v10/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11: 'https://api.vc.bilibili.com/dynamic_svr/v11/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V12: 'https://api.vc.bilibili.com/dynamic_svr/v12/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13: 'https://api.vc.bilibili.com/dynamic_svr/v13/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V14: 'https://api.vc.bilibili.com/dynamic_svr/v14/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V15: 'https://api.vc.bilibili.com/dynamic_svr/v15/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V16: 'https://api.vc.bilibili.com/dynamic_svr/v16/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100: 'https://api.vc.bilibili.com/dynamic_svr/v100/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000: 'https://api.vc.bilibili.com/dynamic_svr/v1000/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000: 'https://api.vc.bilibili.com/dynamic_svr/v10000/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100000: 'https://api.vc.bilibili.com/dynamic_svr/v100000/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000000: 'https://api.vc.bilibili.com/dynamic_svr/v1000000/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000000: 'https://api.vc.bilibili.com/dynamic_svr/v10000000/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', diff --git a/lib/net/bili.js b/lib/net/bili.js index b692d39951..44eb610b27 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -421,42 +421,49 @@ const bili_client = { } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V11, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V12, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V13, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V14, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100000, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V15, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000000, config: { retry: false }, query: { dynamic_id } }), (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V16, + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000000, + config: { retry: false }, + query: { + dynamic_id + } + }), + (dynamic_id) => get({ + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1, config: { retry: false }, query: { dynamic_id From 759a87140e51f8a7feadb3be761d5a63c35812da Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 9 Mar 2024 15:13:51 +0800 Subject: [PATCH 11/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03877f7c4b..1a0a8f25b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## 主要变化(2.8.14) +* f5bdd28 fix: update api getOneDynamicByDyid +* cb6fad0 fix: get_dynamic_detail api (#351) +* 780a3a9 fix: update get_dynamic_detail api (#350) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.13) * addb9c6 fix: ghproxy.com->mirror.ghproxy.com (#333) * b86e756 fix: at错位 diff --git a/package.json b/package.json index 5adffc32ab..8383f7ebbb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.13", + "version": "2.8.14", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From e2976cc9b7d98e1b73a907c4134ba9f15269ef6d Mon Sep 17 00:00:00 2001 From: ypw96 <90349951+ypw96@users.noreply.github.com> Date: Mon, 25 Mar 2024 10:22:16 +0800 Subject: [PATCH 12/74] =?UTF-8?q?docs:=20=E6=96=87=E6=A1=A3=E6=9B=B4?= =?UTF-8?q?=E6=96=B0cookie=E8=8E=B7=E5=8F=96=E6=96=B9=E5=BC=8F=20(#357)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add files via upload * Update README.md 新增COOKIE获取方式 --- README.md | 29 +++++++++++++++++++++++++++++ doc/pic/getCookies2.png | Bin 0 -> 129623 bytes 2 files changed, 29 insertions(+) create mode 100644 doc/pic/getCookies2.png diff --git a/README.md b/README.md index 8a16b8f0ed..b943f0e4ed 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,35 @@ #### 手动获取 +第一种 +进入[B站主页](https://www.bilibili.com/)点击个人头像进入个人主页获取Cookie用于登录 + +Chrome浏览器: + +进入个人主页后 +1. `F12`打开控制台 + +2. F5刷新 + +3. 根据图中找到network/网络 搜索nav,点击找到的nav,点标头,下滑,找到COOKIE全部复制 +![image](doc/pic/getCookies2.png) + +注意!!!!!!!!!!! + +注意!!!!!!!!!!! + +注意!!!!!!!!!!! + +所有网页端获取的COOKIE,每次打开网页端时,都会有概率刷新COOKIE,点击退出账号则会退出当前COOKIE。可以利用Chrome内核的浏览器创建多用户,专门用于获取COOKIE。 + +注意!!!!!!!!!!! + +注意!!!!!!!!!!! + +注意!!!!!!!!!!! + + +第二种 进入[B站主页](https://www.bilibili.com/)获取Cookie用于登录 Chrome浏览器: diff --git a/doc/pic/getCookies2.png b/doc/pic/getCookies2.png new file mode 100644 index 0000000000000000000000000000000000000000..b4cf11ddbc5e2056c83df794e211a2b2f098028f GIT binary patch literal 129623 zcmX_{b97`uxAubxCbn%%Y}+a4Ch zwQE27_k=0ROTfe6z<_{&z)MMrDuaN4@qK>}p~1edP{7o;gMbi$NQnxmx`Uo)L3pFJ zVGaRZLfW_GBi42<9fx*YTY+ae;FrJMy7zv&apHvo(cMburZFtb#=d~?a9%*$6}y%J zGk((%llYVreZ9>w8D>;58=Fdh?-A(X{|#?aXe?h+?@^o4|9^=JIrbv?7Zfwte`5;; ztbXG)SzG2%OGd=@ zt(eC*Bpxh&)M<}KoyfpVA^xW0DE)uKV*8trAmO4K|B~$QC)=S7f)R@({u(A-t1@Z+ zld1c^&rTEu?Oh9y8Yibr`Jd4wF~GuGX|>3d$yr#Gb zE#D6i0m4p1Ms|ObP=buC6i!yDRA?1dr%q8ksKsp7Sj$?nooJ@n#A!&a($u`AYPglU z!OX@cwu>s1x-vFAJS>WGJv==fYZ6uxm-C;0xeyQR-l!XsfyH#(z}EI*;nX5EGBUE= z=ShzsMn^Di7On!LBsi?HeqQtjP!GVW`nfll$?Y+_yewLUv&+uQTWPpQQMJ}6*Y8XW zib=0)suE_?zB`~8oro-n|05t^(|pPd9Uni7d*DPpJS@z?L^N?Y1LpgtluVTwqw&Gd zssBPlp~F_6kR`|M(o$2&j6hIoy6fud;^LHqE&rf2AfrDB5ur#IV@$dKC}=X@`V1X@ zW=T)S(x}oYvjsj{VK3N4MJZoZu@#0`jj}6O{oDs&gC5GwcZAm

if3x}g}Qb}kS8 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 literal 0 HcmV?d00001 From eafa7c7ae490e004ee99f8ab32d28f5365490cc5 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Mar 2024 10:35:22 +0800 Subject: [PATCH 13/74] fix: Cannot read properties of null (reading 'length') (#360) Fixed #360 --- lib/core/searcher.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 07833b4dad..57d2dae851 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -192,14 +192,14 @@ function parseDynamicCard(dynamic_detail_card) { function modifyDynamicRes(res) { const { data, code } = utils.strToJson(res), - { cards = [], has_more, offset } = data || {}; + { cards, has_more, offset } = data || {}; if (code !== 0) { log.error('处理动态数据', '获取动态数据出错,可能是访问太频繁 \n' + res); return null; } - if (!cards.length) { + if (cards == null || !cards || !cards.lengh) { log.warn('处理动态数据', '未找到任何动态信息') } From d9dba6f0ff1c0b248bf44096750ddc1ec2516fa6 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Mar 2024 10:43:38 +0800 Subject: [PATCH 14/74] fix: Cannot read properties of null (reading 'is_liked') --- lib/core/searcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 57d2dae851..4f3fcff1c5 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -63,7 +63,7 @@ function parseDynamicCard(dynamic_detail_card) { /**临时储存单个动态中的信息 */ let obj = {}; const { desc, card, extension, extend_json = "{}", display = {} } = dynamic_detail_card - , { is_liked = 1, user_profile = {} } = desc + , { is_liked = 1, user_profile = {} } = desc || {} , { info = {} } = user_profile , cardToJson = strToJson(card) , extendjsonToJson = strToJson(extend_json) From d337fb235d2c3d73f54d0276420de292a48b765e Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Mar 2024 15:15:20 +0800 Subject: [PATCH 15/74] =?UTF-8?q?fix:=20=E6=9F=A5=E8=AF=A2=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=AF=A6=E6=83=85=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=A4=B1?= =?UTF-8?q?=E6=95=88=20(#349)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/api.bili.js | 9 +--- lib/net/bili.js | 101 ++++++++++++-------------------------------- 2 files changed, 29 insertions(+), 81 deletions(-) diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index 61a91f3d98..c17cd28c06 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -5,14 +5,7 @@ module.exports = Object.freeze({ DYNAMIC_REPOST_SHARE: 'https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/share', DYNAMIC_SVR_CREATE_DRAW: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create_draw', DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10: 'https://api.vc.bilibili.com/dynamic_svr/v10/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100: 'https://api.vc.bilibili.com/dynamic_svr/v100/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000: 'https://api.vc.bilibili.com/dynamic_svr/v1000/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000: 'https://api.vc.bilibili.com/dynamic_svr/v10000/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100000: 'https://api.vc.bilibili.com/dynamic_svr/v100000/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000000: 'https://api.vc.bilibili.com/dynamic_svr/v1000000/dynamic_svr/get_dynamic_detail', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000000: 'https://api.vc.bilibili.com/dynamic_svr/v10000000/dynamic_svr/get_dynamic_detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V: 'https://api.vc.bilibili.com/dynamic_svr/v{{v}}/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', diff --git a/lib/net/bili.js b/lib/net/bili.js index 44eb610b27..efe8ae1e7a 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -412,81 +412,36 @@ const bili_client = { return dyid }) }, - _getOneDynamicByDyid: new Line('获取一个动态的细节', [ - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V100000, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1000000, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V10000000, - config: { retry: false }, - query: { - dynamic_id - } - }), - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V1, - config: { retry: false }, - query: { - dynamic_id + _getOneDynamicByDyid: new Line( + '获取一个动态的细节', + Array(10) + .fill( + (dynamic_id) => get({ + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V.replace('{{v}}', Math.floor(Math.random() * 10 ** 10)), + config: { retry: false }, + query: { + dynamic_id + } + }) + ) + , responseText => { + const + res = strToJson(responseText), + { code, data } = res, + { card } = data || {}; + switch (code) { + case 0: + if (card) { + return [false, card, `ok`]; + } else { + return [false, undefined, `动态不存在`]; + } + case 500207: + return [false, undefined, `该动态为包月充电专属可以给UP主充电后观看`]; + default: + return [true, undefined, `获取动态数据出错:\n${responseText}`] } }), - ], responseText => { - const - res = strToJson(responseText), - { code, data } = res, - { card } = data || {}; - switch (code) { - case 0: - if (card) { - return [false, card, `ok`]; - } else { - return [false, undefined, `动态不存在`]; - } - case 500207: - return [false, undefined, `该动态为包月充电专属可以给UP主充电后观看`]; - default: - return [true, undefined, `获取动态数据出错:\n${responseText}`] - } - }), /** * 获取一个动态的细节 * @param {string} dynamic_id From 7b6356ac252f30cea79240bde3e3f7e7594a2f2f Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Mar 2024 15:44:23 +0800 Subject: [PATCH 16/74] =?UTF-8?q?fix:=20=20=E9=A3=8E=E6=8E=A7=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=8A=A8=E6=80=81=E5=85=A8=E4=B8=BA=E8=BF=87=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 2b0296f4a5..61d19db061 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -370,7 +370,7 @@ class Monitor extends Searcher { } /* 超过指定时间退出 */ - if (now_ts - create_time > max_create_time * 86400) { + if (create_time && now_ts - create_time > max_create_time * 86400) { log.info("筛选动态", `过时动态(https://t.bilibili.com/${dyid})`) return false } From 7a8682ce761b3c81ebb0137e579e9515367bc7cc Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Mar 2024 16:16:15 +0800 Subject: [PATCH 17/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a0a8f25b5..1d31b9241f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # CHANGELOG +## 主要变化(2.8.15) +* 7b6356a fix: 风控导致动态全为过时 +* d337fb2 fix: 查询动态详情的接口失效 (#349) +* d9dba6f fix: Cannot read properties of null (reading 'is_liked') +* eafa7c7 fix: Cannot read properties of null (reading 'length') (#360) +* e2976cc docs: 文档更新cookie获取方式 (#357) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.14) * f5bdd28 fix: update api getOneDynamicByDyid * cb6fad0 fix: get_dynamic_detail api (#351) diff --git a/package.json b/package.json index 8383f7ebbb..7e81c8c2ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.14", + "version": "2.8.15", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 469a6dc7b572d2f03157052f53348c41425237b8 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 5 Apr 2024 10:10:01 +0800 Subject: [PATCH 18/74] fix: add getOneDynamicByDyid v1 --- lib/core/searcher.js | 2 +- lib/net/bili.js | 29 +++++++++++++++++++---------- lib/utils.js | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 4f3fcff1c5..0b99bf3640 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -67,7 +67,7 @@ function parseDynamicCard(dynamic_detail_card) { , { info = {} } = user_profile , cardToJson = strToJson(card) , extendjsonToJson = strToJson(extend_json) - , { add_on_card_info = [] } = display + , { add_on_card_info = [] } = display || {} , { item } = cardToJson; const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); /* 转发者的UID */ diff --git a/lib/net/bili.js b/lib/net/bili.js index efe8ae1e7a..0a7afafbc1 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -414,16 +414,25 @@ const bili_client = { }, _getOneDynamicByDyid: new Line( '获取一个动态的细节', - Array(10) - .fill( - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V.replace('{{v}}', Math.floor(Math.random() * 10 ** 10)), - config: { retry: false }, - query: { - dynamic_id - } - }) - ) + [ + (dynamic_id) => get({ + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V.replace('{{v}}', 1), + config: { retry: false }, + query: { + dynamic_id + } + }), + ...Array(10) + .fill( + (dynamic_id) => get({ + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V.replace('{{v}}', Math.floor(Math.random() * 10 ** 10)), + config: { retry: false }, + query: { + dynamic_id + } + }) + ) + ] , responseText => { const res = strToJson(responseText), diff --git a/lib/utils.js b/lib/utils.js index 7eb6ba7efd..54fcf60c31 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -45,7 +45,7 @@ const utils = { const obj = JSON.parse(str); return typeof obj === 'object' ? obj : false } catch (e) { - utils.log.error("json解析", e) + utils.log.error("json解析", e + "\n" + params) return false; } } else { From 364bcd1325041c733d48dcbb87d0a1b9ca1d08d4 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 5 Apr 2024 10:12:55 +0800 Subject: [PATCH 19/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d31b9241f..9460f7cad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 主要变化(2.8.16) +* 469a6dc fix: add getOneDynamicByDyid v1 + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.15) * 7b6356a fix: 风控导致动态全为过时 * d337fb2 fix: 查询动态详情的接口失效 (#349) diff --git a/package.json b/package.json index 7e81c8c2ad..c12162ea7f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.15", + "version": "2.8.16", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 7e4650ced45ad952c2f96fd17db050d7703d5201 Mon Sep 17 00:00:00 2001 From: JianJia2018 <39438074+JianJia2018@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:17:05 +0800 Subject: [PATCH 20/74] =?UTF-8?q?feat:=20env=E5=8F=AF=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89UA=20(#371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 简佳 <15779599039@163.com> --- env.example.js | 5 ++++- lib/net/http.js | 2 +- main.js | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/env.example.js b/env.example.js index 967ca7a2ab..7deafe1eb0 100644 --- a/env.example.js +++ b/env.example.js @@ -5,6 +5,7 @@ module.exports = Object.freeze({ * - `NOTE` 帐号备注 * - `NUMBER` 表示是第几个账号 * - `CLEAR` 是否启用清理功能 + * - `ACCOUNT_UA` 账号UA, 可在浏览器控制台输入 navigator.userAgent 查看 * ## 高级功能 * - `ENABLE_CHAT_CAPTCHA_OCR` 开启评论验证码识别 使用方法见README * - `ENABLE_MULTIPLE_ACCOUNT` 是否启用多账号 @@ -25,6 +26,7 @@ module.exports = Object.freeze({ NOTE: "", NUMBER: 1, CLEAR: true, + ACCOUNT_UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", ENABLE_CHAT_CAPTCHA_OCR: "", ENABLE_MULTIPLE_ACCOUNT: false, @@ -59,7 +61,8 @@ module.exports = Object.freeze({ NOTE: "", NUMBER: 1, CLEAR: true, - WAIT: 60 * 1000 + WAIT: 60 * 1000, + ACCOUNT_UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" } ], diff --git a/lib/net/http.js b/lib/net/http.js index 37e8e4e05b..9b43559c74 100644 --- a/lib/net/http.js +++ b/lib/net/http.js @@ -56,7 +56,7 @@ const DEFAULT_REDIRECT = false; /**错误尝试次数 */ const DEFAULT_RETRY_TIMES = 6; /**Google Chrome */ -const DEFAULT_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'; +const DEFAULT_UA = process.env.ACCOUNT_UA || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'; /**默认url编码 */ const DEFAULT_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=UTF-8'; /** diff --git a/main.js b/main.js index 30b86561c9..989b5c5b8c 100644 --- a/main.js +++ b/main.js @@ -37,6 +37,7 @@ async function main() { process.env.NUMBER = acco.NUMBER; process.env.CLEAR = acco.CLEAR; process.env.NOTE = acco.NOTE; + process.env.ACCOUNT_UA = acco.ACCOUNT_UA; const err_msg = await main(); if (err_msg) { return err_msg From 5b33ae3bb6e78c03052b6305c29548f2e69a1e0f Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 12 Apr 2024 07:59:15 +0800 Subject: [PATCH 21/74] =?UTF-8?q?fix:=20=E8=AF=BB=E5=8F=96uid=E5=87=BA?= =?UTF-8?q?=E9=94=99=20(#369)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #369 --- lib/net/bili.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/net/bili.js b/lib/net/bili.js index 0a7afafbc1..50b539a695 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -440,10 +440,10 @@ const bili_client = { { card } = data || {}; switch (code) { case 0: - if (card) { + if (card && responseText.length > 100) { return [false, card, `ok`]; } else { - return [false, undefined, `动态不存在`]; + return [false, undefined, `获取动态数据异常:\n${responseText}`]; } case 500207: return [false, undefined, `该动态为包月充电专属可以给UP主充电后观看`]; From 5aa50484fe49469e57604de43fb5f73987f3072f Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 12 Apr 2024 07:59:55 +0800 Subject: [PATCH 22/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9460f7cad8..a1a2971e37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 主要变化(2.8.17) +* 5b33ae3 fix: 读取uid出错 (#369) +* 7e4650c feat: env可自定义UA (#371) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.16) * 469a6dc fix: add getOneDynamicByDyid v1 diff --git a/package.json b/package.json index c12162ea7f..fab54dcee1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.16", + "version": "2.8.17", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 60e211ef3a70952f940905c4a4c3b302041e05af Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 12 Apr 2024 14:47:59 +0800 Subject: [PATCH 23/74] =?UTF-8?q?fix:=20=E8=AF=BB=E5=8F=96uid=E5=87=BA?= =?UTF-8?q?=E9=94=99=20(#369)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #369 --- lib/net/bili.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/net/bili.js b/lib/net/bili.js index 50b539a695..505a7ed0f0 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -437,10 +437,11 @@ const bili_client = { const res = strToJson(responseText), { code, data } = res, - { card } = data || {}; + { card } = data || {}, + { desc } = card || {}; switch (code) { case 0: - if (card && responseText.length > 100) { + if (card && desc) { return [false, card, `ok`]; } else { return [false, undefined, `获取动态数据异常:\n${responseText}`]; From e9c341dce02c83d6b0a204c337008cf123645c9a Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 12 Apr 2024 14:49:42 +0800 Subject: [PATCH 24/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1a2971e37..f9788ccc6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 主要变化(2.8.17) +* 60e211e fix: 读取uid出错 (#369) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.17) * 5b33ae3 fix: 读取uid出错 (#369) * 7e4650c feat: env可自定义UA (#371) diff --git a/package.json b/package.json index fab54dcee1..ef8b6e8eb0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.17", + "version": "2.8.18", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 93d372761a15f477ab8b9179f6204aade01bda74 Mon Sep 17 00:00:00 2001 From: ypw96 <90349951+ypw96@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:30:54 +0800 Subject: [PATCH 25/74] fix: searcher.js typo fix (#379) --- lib/core/searcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 0b99bf3640..44beb17614 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -199,7 +199,7 @@ function modifyDynamicRes(res) { return null; } - if (cards == null || !cards || !cards.lengh) { + if (cards == null || !cards || !cards.length) { log.warn('处理动态数据', '未找到任何动态信息') } From ded981e4d7ae34df59d581de7d69752ce1699a50 Mon Sep 17 00:00:00 2001 From: shanmite Date: Thu, 25 Apr 2024 08:46:07 +0800 Subject: [PATCH 26/74] =?UTF-8?q?fix:=20=E5=8A=A8=E6=80=81=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E8=A7=A3=E6=9E=90=E5=87=BA=E9=94=99=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=81=9C=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 196 ++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 96 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 44beb17614..a487a98e12 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -62,88 +62,33 @@ function parseDynamicCard(dynamic_detail_card) { const { strToJson } = utils; /**临时储存单个动态中的信息 */ let obj = {}; - const { desc, card, extension, extend_json = "{}", display = {} } = dynamic_detail_card - , { is_liked = 1, user_profile = {} } = desc || {} - , { info = {} } = user_profile - , cardToJson = strToJson(card) - , extendjsonToJson = strToJson(extend_json) - , { add_on_card_info = [] } = display || {} - , { item } = cardToJson; - const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); - /* 转发者的UID */ - obj.uid = desc.uid - /* 转发者的name */ - obj.uname = info.uname || '' - /* 动态是否点过赞 */ - obj.is_liked = is_liked > 0 - /* 动态的ts10 */ - obj.create_time = desc.timestamp - /* 动态类型 */ - obj.type = desc.type - /* 用于发送评论 */ - obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; - /* 用于发送评论 */ - obj.chat_type = dy_type2chat_type.get(obj.type) || 0; - /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.dynamic_id = desc.dynamic_id_str; - /* 定位@信息 */ - obj.ctrl = (extendjsonToJson.ctrl) || []; - /* 预约抽奖信息 */ - if (add_on_card_info.length > 0) { - const [status, oid_str, text] = add_on_card_info - .filter(it => typeof it.reserve_attach_card !== 'undefined' - && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' - && typeof it.reserve_attach_card.reserve_button !== 'undefined') - .map(({ reserve_attach_card }) => [ - reserve_attach_card.reserve_button.status, - reserve_attach_card.oid_str, - reserve_attach_card.reserve_lottery.text])[0] || []; - if (status === 1) { - obj.reserve_id = oid_str; - obj.reserve_lottery_text = text; - } - } - if (extendjsonToJson[""]) { - let r = extendjsonToJson[""].reserve || {}; - let { reserve_id, reserve_lottery } = r; - if (reserve_lottery === 1) { - obj.reserve_id = reserve_id + ""; - obj.reserve_lottery_text = "信息丢失"; - } - } - if (extend_json.match(/"":\{"lottery/)) { - obj.is_charge_lottery = true - } - /* 是否有官方抽奖 */ - obj.hasOfficialLottery = extension && extension.lott && true; - /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ - obj.description = - (item && ((item.content || '') + (item.description || ''))) - || ( - (cardToJson.dynamic || '') - + (cardToJson.desc || '') - + (cardToJson.vest && cardToJson.vest.content || '') - ) - || ''; - /* 转发 */ - if (obj.type === 1) { - const { origin_extension, origin, origin_extend_json = "{}" } = cardToJson - , originToJson = strToJson(origin) - , { add_on_card_info = [] } = display.origin || {} - , originExtendjsonToJson = strToJson(origin_extend_json) - , { user, item } = originToJson; - /* 源动态的ts10 */ - obj.origin_create_time = desc.origin.timestamp; - /* 被转发者的UID */ - obj.origin_uid = desc.origin.uid; - /* 源动态类型 */ - obj.origin_type = desc.orig_type - /* 被转发者的rid(用于发评论) */ - obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; + try { + const { desc = {}, card = "{}", extension = {}, extend_json = "{}", display = {} } = dynamic_detail_card + , { is_liked = 1, user_profile = {} } = desc || {} + , { info = {} } = user_profile || {} + , cardToJson = strToJson(card) + , extendjsonToJson = strToJson(extend_json) + , { add_on_card_info = [] } = display || {} + , { item = {} } = cardToJson; + const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); + /* 转发者的UID */ + obj.uid = desc.uid + /* 转发者的name */ + obj.uname = info.uname || '' + /* 动态是否点过赞 */ + obj.is_liked = is_liked > 0 + /* 动态的ts10 */ + obj.create_time = desc.timestamp + /* 动态类型 */ + obj.type = desc.type + /* 用于发送评论 */ + obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; /* 用于发送评论 */ - obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 - /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.origin_dynamic_id = desc.orig_dy_id_str; + obj.chat_type = dy_type2chat_type.get(obj.type) || 0; + /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ + obj.dynamic_id = desc.dynamic_id_str; + /* 定位@信息 */ + obj.ctrl = (extendjsonToJson.ctrl) || []; /* 预约抽奖信息 */ if (add_on_card_info.length > 0) { const [status, oid_str, text] = add_on_card_info @@ -155,30 +100,89 @@ function parseDynamicCard(dynamic_detail_card) { reserve_attach_card.oid_str, reserve_attach_card.reserve_lottery.text])[0] || []; if (status === 1) { - obj.origin_reserve_id = oid_str; - obj.origin_reserve_lottery_text = text; + obj.reserve_id = oid_str; + obj.reserve_lottery_text = text; } } - if (originExtendjsonToJson[""]) { - let r = originExtendjsonToJson[""].reserve || {}; + if (extendjsonToJson[""]) { + let r = extendjsonToJson[""].reserve || {}; let { reserve_id, reserve_lottery } = r; if (reserve_lottery === 1) { - obj.origin_reserve_id = reserve_id + ""; - obj.origin_reserve_lottery_text = "信息丢失"; + obj.reserve_id = reserve_id + ""; + obj.reserve_lottery_text = "信息丢失"; } } - if (origin_extend_json.match(/"":\{"lottery/)) { - obj.origin_is_charge_lottery = true + if (extend_json.match(/"":\{"lottery/)) { + obj.is_charge_lottery = true } /* 是否有官方抽奖 */ - obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; - /* 被转发者的name */ - obj.origin_uname = (user && (user.name || user.uname)) || ''; - /* 被转发者的描述 */ - obj.origin_description = - (item && (item.content || '' + item.description || '')) - || (originToJson.dynamic || '' + originToJson.desc || '') + obj.hasOfficialLottery = extension && extension.lott && true; + /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ + obj.description = + (item && ((item.content || '') + (item.description || ''))) + || ( + (cardToJson.dynamic || '') + + (cardToJson.desc || '') + + (cardToJson.vest && cardToJson.vest.content || '') + ) || ''; + /* 转发 */ + if (obj.type === 1) { + const { origin_extension = {}, origin = "{}", origin_extend_json = "{}" } = cardToJson + , originToJson = strToJson(origin) + , { add_on_card_info = [] } = display.origin || {} + , originExtendjsonToJson = strToJson(origin_extend_json) + , { user = {}, item = {} } = originToJson; + /* 源动态的ts10 */ + obj.origin_create_time = desc.origin.timestamp; + /* 被转发者的UID */ + obj.origin_uid = desc.origin.uid; + /* 源动态类型 */ + obj.origin_type = desc.orig_type + /* 被转发者的rid(用于发评论) */ + obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; + /* 用于发送评论 */ + obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 + /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ + obj.origin_dynamic_id = desc.orig_dy_id_str; + /* 预约抽奖信息 */ + if (add_on_card_info.length > 0) { + const [status, oid_str, text] = add_on_card_info + .filter(it => typeof it.reserve_attach_card !== 'undefined' + && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' + && typeof it.reserve_attach_card.reserve_button !== 'undefined') + .map(({ reserve_attach_card }) => [ + reserve_attach_card.reserve_button.status, + reserve_attach_card.oid_str, + reserve_attach_card.reserve_lottery.text])[0] || []; + if (status === 1) { + obj.origin_reserve_id = oid_str; + obj.origin_reserve_lottery_text = text; + } + } + if (originExtendjsonToJson[""]) { + let r = originExtendjsonToJson[""].reserve || {}; + let { reserve_id, reserve_lottery } = r; + if (reserve_lottery === 1) { + obj.origin_reserve_id = reserve_id + ""; + obj.origin_reserve_lottery_text = "信息丢失"; + } + } + if (origin_extend_json.match(/"":\{"lottery/)) { + obj.origin_is_charge_lottery = true + } + /* 是否有官方抽奖 */ + obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; + /* 被转发者的name */ + obj.origin_uname = (user && (user.name || user.uname)) || ''; + /* 被转发者的描述 */ + obj.origin_description = + (item && (item.content || '' + item.description || '')) + || (originToJson.dynamic || '' + originToJson.desc || '') + || ''; + } + } catch (e) { + log.error("动态卡片解析", e) } return obj From d9f6bf247cb545f0fd1050376123d0ab81a130bf Mon Sep 17 00:00:00 2001 From: Nevidebla <54260027+Nevidebla@users.noreply.github.com> Date: Thu, 25 Apr 2024 08:55:49 +0800 Subject: [PATCH 27/74] =?UTF-8?q?feat:=20=E4=B8=AD=E5=A5=96=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E5=B1=8F=E8=94=BD=E8=87=AA=E5=8A=A8=E5=9B=9E=E5=A4=8D?= =?UTF-8?q?=20(#381)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 中奖检测屏蔽自动回复 根据消息类型屏蔽掉关注自动回复和营销广告,避免误判 * fix --- lib/net/bili.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net/bili.js b/lib/net/bili.js index 505a7ed0f0..466a141e2a 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -319,7 +319,7 @@ const bili_client = { const msgs = res.data.messages if (msgs instanceof Array) { log.info('私信细节', `${talker_id}有${size}条未读私信`) - return msgs.map(it => it.content).join('\n') + return msgs.filter(it => ![5, 8, 9, 10, 11].includes(it.msg_source)).map(it => it.content).join('\n') } else { log.warn('私信细节', `${talker_id}无私信`) } From 5a86a0407ad345fa6e70191c30303065f537765d Mon Sep 17 00:00:00 2001 From: shanmite Date: Thu, 25 Apr 2024 08:57:47 +0800 Subject: [PATCH 28/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9788ccc6f..364db030a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## 主要变化(2.8.19) +* d9f6bf2 feat: 中奖检测屏蔽自动回复 (#381) +* ded981e fix: 动态卡片解析出错导致程序停止 +* 93d3727 fix: searcher.js typo fix (#379) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.17) * 60e211e fix: 读取uid出错 (#369) diff --git a/package.json b/package.json index ef8b6e8eb0..8e72c14871 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.18", + "version": "2.8.19", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From df3e97d3bfb1fe555815eb6de44dbce84dc5410b Mon Sep 17 00:00:00 2001 From: shanmite Date: Thu, 25 Apr 2024 09:05:16 +0800 Subject: [PATCH 29/74] ci: fix "an artifact with this name already exists on the workflow run" --- .github/workflows/docker.yml | 2 +- .github/workflows/mirror.yml | 2 +- .github/workflows/npmp.yml | 2 +- .github/workflows/pkg.yml | 14 +++++++------- script/build/pkg.sh | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 56525898a4..8f7613d81c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index 0b1b8f301d..329102d235 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Mirror + trigger CI diff --git a/.github/workflows/npmp.yml b/.github/workflows/npmp.yml index f50ec67a6d..dbaf625518 100644 --- a/.github/workflows/npmp.yml +++ b/.github/workflows/npmp.yml @@ -12,7 +12,7 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: JS-DevTools/npm-publish@v1 with: token: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/pkg.yml b/.github/workflows/pkg.yml index 0a4be6a1a9..407301d475 100644 --- a/.github/workflows/pkg.yml +++ b/.github/workflows/pkg.yml @@ -30,16 +30,16 @@ jobs: # nodev: 12 steps: - name: "Checkout codes" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: "Use Node.js" - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "*" - name: "Pkg this" run: | npm run pkg "node${{ matrix.nodev }}-${{ matrix.platform }}-x64" - name: "Upload to artifact" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: node${{ matrix.nodev }}-${{ matrix.platform }}-x64 path: "dist/*.zip" @@ -62,14 +62,14 @@ jobs: - platform: alpine steps: - name: "Checkout codes" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: "Pkg this" run: | - npm run pkg "${{ matrix.platform }}-arm64" + npm run pkg "node18-${{ matrix.platform }}-arm64" - name: "Upload to artifact" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: arm64 + name: node18-${{ matrix.platform }}-arm64 path: "dist/*.zip" - name: "Upload to release draft" uses: xresloader/upload-to-github-release@v1 diff --git a/script/build/pkg.sh b/script/build/pkg.sh index 6a9da41843..dbf6f02057 100755 --- a/script/build/pkg.sh +++ b/script/build/pkg.sh @@ -28,12 +28,12 @@ mkdir -p $TARGET_DIR npm install if [[ "$1" == *"arm"* ]]; then - OUTFILE="$TARGET_DIR/lottery-auto-script-node18-$1" + OUTFILE="$TARGET_DIR/lottery-auto-script-$1" sudo podman run --rm --privileged multiarch/qemu-user-static --reset -p yes podman run -it \ --rm \ -v ${PWD}:/root/lottery \ - shanmite/pkg-arm64 -t "node18.5.0-$1" -o "$OUTFILE" . + shanmite/pkg-arm64 -t "node18-$1" -o "$OUTFILE" . elif [[ "$1" == *"x64"* ]]; then OUTFILE="$TARGET_DIR/lottery-auto-script-$1" npx pkg -t "$1" -o "$OUTFILE" . From 666c057194c69901e143a34224f26844af41ff05 Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 27 Apr 2024 17:14:44 +0800 Subject: [PATCH 30/74] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=E6=96=B0?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=9B=BF=E6=8D=A2=E5=8A=A8=E6=80=81=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E8=80=81=E6=8E=A5=E5=8F=A3=20(#382)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 161 +++++++++++++++++-------------------------- lib/net/api.bili.js | 2 +- lib/net/bili.js | 26 ++----- 3 files changed, 73 insertions(+), 116 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index a487a98e12..59eb9692b4 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -55,131 +55,100 @@ const { log } = utils * @property {number} type * @property {boolean} hasOfficialLottery 是否官方 * - * @param {object} dynamic_detail_card + * @param {object} ditem * @return {UsefulDynamicInfo} */ -function parseDynamicCard(dynamic_detail_card) { - const { strToJson } = utils; +function parseDynamicCard(ditem) { /**临时储存单个动态中的信息 */ let obj = {}; try { - const { desc = {}, card = "{}", extension = {}, extend_json = "{}", display = {} } = dynamic_detail_card - , { is_liked = 1, user_profile = {} } = desc || {} - , { info = {} } = user_profile || {} - , cardToJson = strToJson(card) - , extendjsonToJson = strToJson(extend_json) - , { add_on_card_info = [] } = display || {} - , { item = {} } = cardToJson; - const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); + const dy_typeenum2num = new Map([ + ["DYNAMIC_TYPE_FORWARD", 1], + ["DYNAMIC_TYPE_DRAW", 2], + ["DYNAMIC_TYPE_WORD", 4], + ["DYNAMIC_TYPE_AV", 8], + ["DYNAMIC_TYPE_ARTICLE", 64] + ]); /* 转发者的UID */ - obj.uid = desc.uid + obj.uid = ditem?.modules?.module_author?.mid || 0 /* 转发者的name */ - obj.uname = info.uname || '' + obj.uname = ditem?.modules?.module_author?.name || '' /* 动态是否点过赞 */ - obj.is_liked = is_liked > 0 + obj.is_liked = ditem?.modules?.module_stat?.like?.status || false /* 动态的ts10 */ - obj.create_time = desc.timestamp + obj.create_time = ditem?.modules?.module_author?.pub_ts || 0 /* 动态类型 */ - obj.type = desc.type + obj.type = dy_typeenum2num.get(ditem?.type) || 0 /* 用于发送评论 */ - obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; + obj.rid_str = ditem?.basic?.comment_id_str || "" /* 用于发送评论 */ - obj.chat_type = dy_type2chat_type.get(obj.type) || 0; + obj.chat_type = ditem?.basic?.comment_type || 0 /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.dynamic_id = desc.dynamic_id_str; + obj.dynamic_id = ditem?.id_str || "" /* 定位@信息 */ - obj.ctrl = (extendjsonToJson.ctrl) || []; - /* 预约抽奖信息 */ - if (add_on_card_info.length > 0) { - const [status, oid_str, text] = add_on_card_info - .filter(it => typeof it.reserve_attach_card !== 'undefined' - && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' - && typeof it.reserve_attach_card.reserve_button !== 'undefined') - .map(({ reserve_attach_card }) => [ - reserve_attach_card.reserve_button.status, - reserve_attach_card.oid_str, - reserve_attach_card.reserve_lottery.text])[0] || []; - if (status === 1) { - obj.reserve_id = oid_str; - obj.reserve_lottery_text = text; + obj.ctrl = []; + /* 是否有官方抽奖 */ + obj.hasOfficialLottery = false + /* 转发描述 */ + obj.description = "" + let _total_len = 0; + ditem?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { + if (node.type === "RICH_TEXT_NODE_TYPE_AT") { + obj.ctrl.push({ + data: node.rid, + location: _total_len, + length: node.text.length, + type: 1 + }) } - } - if (extendjsonToJson[""]) { - let r = extendjsonToJson[""].reserve || {}; - let { reserve_id, reserve_lottery } = r; - if (reserve_lottery === 1) { - obj.reserve_id = reserve_id + ""; - obj.reserve_lottery_text = "信息丢失"; + /* 是否有官方抽奖 */ + if (node.type === "RICH_TEXT_NODE_TYPE_LOTTERY") { + obj.hasOfficialLottery = true } - } - if (extend_json.match(/"":\{"lottery/)) { + obj.description += node.orig_text + _total_len += node.text.length + }) + /* 预约抽奖信息 */ + obj.reserve_id = ditem?.modules?.module_dynamic?.additional?.reserve?.rid || 0 + obj.reserve_lottery_text = ditem?.modules?.module_dynamic?.additional?.reserve?.title || "信息丢失" + /* 充电抽奖 */ + if (ditem?.modules?.module_dynamic?.additional?.type === "ADDITIONAL_TYPE_UPOWER_LOTTERY") { obj.is_charge_lottery = true } - /* 是否有官方抽奖 */ - obj.hasOfficialLottery = extension && extension.lott && true; - /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ - obj.description = - (item && ((item.content || '') + (item.description || ''))) - || ( - (cardToJson.dynamic || '') - + (cardToJson.desc || '') - + (cardToJson.vest && cardToJson.vest.content || '') - ) - || ''; /* 转发 */ if (obj.type === 1) { - const { origin_extension = {}, origin = "{}", origin_extend_json = "{}" } = cardToJson - , originToJson = strToJson(origin) - , { add_on_card_info = [] } = display.origin || {} - , originExtendjsonToJson = strToJson(origin_extend_json) - , { user = {}, item = {} } = originToJson; - /* 源动态的ts10 */ - obj.origin_create_time = desc.origin.timestamp; /* 被转发者的UID */ - obj.origin_uid = desc.origin.uid; + obj.origin_uid = ditem?.orig?.modules?.module_author?.mid || 0 + /* 被转发者的name */ + obj.origin_uname = ditem?.orig?.modules?.module_author?.name || '' + /* 源动态的ts10 */ + obj.origin_create_time = ditem?.orig?.modules?.module_author?.pub_ts || 0 /* 源动态类型 */ - obj.origin_type = desc.orig_type + obj.origin_type = dy_typeenum2num.get(ditem?.orig?.type) || 0 /* 被转发者的rid(用于发评论) */ - obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; + obj.origin_rid_str = ditem?.orig?.basic?.comment_id_str || "" /* 用于发送评论 */ - obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 + obj.origin_chat_type = ditem?.orig?.basic?.comment_type || 0 /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.origin_dynamic_id = desc.orig_dy_id_str; + obj.origin_dynamic_id = ditem?.orig?.id_str || "" /* 预约抽奖信息 */ - if (add_on_card_info.length > 0) { - const [status, oid_str, text] = add_on_card_info - .filter(it => typeof it.reserve_attach_card !== 'undefined' - && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' - && typeof it.reserve_attach_card.reserve_button !== 'undefined') - .map(({ reserve_attach_card }) => [ - reserve_attach_card.reserve_button.status, - reserve_attach_card.oid_str, - reserve_attach_card.reserve_lottery.text])[0] || []; - if (status === 1) { - obj.origin_reserve_id = oid_str; - obj.origin_reserve_lottery_text = text; - } - } - if (originExtendjsonToJson[""]) { - let r = originExtendjsonToJson[""].reserve || {}; - let { reserve_id, reserve_lottery } = r; - if (reserve_lottery === 1) { - obj.origin_reserve_id = reserve_id + ""; - obj.origin_reserve_lottery_text = "信息丢失"; - } - } - if (origin_extend_json.match(/"":\{"lottery/)) { + obj.origin_reserve_id = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.rid || 0 + obj.origin_reserve_lottery_text = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.title || "信息丢失" + /* 充电抽奖 */ + if (ditem?.orig?.modules?.module_dynamic?.additional?.type === "ADDITIONAL_TYPE_UPOWER_LOTTERY") { obj.origin_is_charge_lottery = true } /* 是否有官方抽奖 */ - obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; - /* 被转发者的name */ - obj.origin_uname = (user && (user.name || user.uname)) || ''; - /* 被转发者的描述 */ - obj.origin_description = - (item && (item.content || '' + item.description || '')) - || (originToJson.dynamic || '' + originToJson.desc || '') - || ''; + obj.origin_hasOfficialLottery = false + /* 转发描述 */ + obj.origin_description = "" + ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { + /* 是否有官方抽奖 */ + if (node.type === "RICH_TEXT_NODE_TYPE_LOTTERY") { + obj.origin_hasOfficialLottery = true + } + obj.origin_description += node.orig_text + }) } } catch (e) { log.error("动态卡片解析", e) diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index c17cd28c06..245240b554 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -5,7 +5,7 @@ module.exports = Object.freeze({ DYNAMIC_REPOST_SHARE: 'https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/share', DYNAMIC_SVR_CREATE_DRAW: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create_draw', DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', - DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V: 'https://api.vc.bilibili.com/dynamic_svr/v{{v}}/dynamic_svr/get_dynamic_detail', + X_POLYMER_WEB_DYNAMIC_V1_DETAIL: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', diff --git a/lib/net/bili.js b/lib/net/bili.js index 466a141e2a..d824ff8417 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -415,39 +415,27 @@ const bili_client = { _getOneDynamicByDyid: new Line( '获取一个动态的细节', [ - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V.replace('{{v}}', 1), + (id) => get({ + url: API.X_POLYMER_WEB_DYNAMIC_V1_DETAIL, config: { retry: false }, query: { - dynamic_id + id } }), - ...Array(10) - .fill( - (dynamic_id) => get({ - url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL_V.replace('{{v}}', Math.floor(Math.random() * 10 ** 10)), - config: { retry: false }, - query: { - dynamic_id - } - }) - ) ] , responseText => { const res = strToJson(responseText), { code, data } = res, - { card } = data || {}, - { desc } = card || {}; + { item } = data || {}, + { id_str } = item || {}; switch (code) { case 0: - if (card && desc) { - return [false, card, `ok`]; + if (item && id_str) { + return [false, item, `ok`]; } else { return [false, undefined, `获取动态数据异常:\n${responseText}`]; } - case 500207: - return [false, undefined, `该动态为包月充电专属可以给UP主充电后观看`]; default: return [true, undefined, `获取动态数据出错:\n${responseText}`] } From 1a08c0a17b4ac83680ca0d193e9228e7b4cd5416 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 29 Apr 2024 10:15:01 +0800 Subject: [PATCH 31/74] =?UTF-8?q?fix:=20=E8=AF=9D=E9=A2=98uid=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=8E=B7=E5=8F=96=E4=BD=BF=E7=94=A8=E8=80=81=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 132 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 59eb9692b4..88fa1a7586 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -157,6 +157,136 @@ function parseDynamicCard(ditem) { return obj } +/** + * @param {object} dynamic_detail_card + * @return {UsefulDynamicInfo} + */ +function oldParseDynamicCard(dynamic_detail_card) { + const { strToJson } = utils; + /**临时储存单个动态中的信息 */ + let obj = {}; + const { desc, card, extension, extend_json = "{}", display = {} } = dynamic_detail_card + , { is_liked = 1, user_profile = {} } = desc + , { info = {} } = user_profile + , cardToJson = strToJson(card) + , extendjsonToJson = strToJson(extend_json) + , { add_on_card_info = [] } = display + , { item } = cardToJson; + const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); + /* 转发者的UID */ + obj.uid = desc.uid + /* 转发者的name */ + obj.uname = info.uname || '' + /* 动态是否点过赞 */ + obj.is_liked = is_liked > 0 + /* 动态的ts10 */ + obj.create_time = desc.timestamp + /* 动态类型 */ + obj.type = desc.type + /* 用于发送评论 */ + obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; + /* 用于发送评论 */ + obj.chat_type = dy_type2chat_type.get(obj.type) || 0; + /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ + obj.dynamic_id = desc.dynamic_id_str; + /* 定位@信息 */ + obj.ctrl = (extendjsonToJson.ctrl) || []; + /* 预约抽奖信息 */ + if (add_on_card_info.length > 0) { + const [status, oid_str, text] = add_on_card_info + .filter(it => typeof it.reserve_attach_card !== 'undefined' + && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' + && typeof it.reserve_attach_card.reserve_button !== 'undefined') + .map(({ reserve_attach_card }) => [ + reserve_attach_card.reserve_button.status, + reserve_attach_card.oid_str, + reserve_attach_card.reserve_lottery.text])[0] || []; + if (status === 1) { + obj.reserve_id = oid_str; + obj.reserve_lottery_text = text; + } + } + if (extendjsonToJson[""]) { + let r = extendjsonToJson[""].reserve || {}; + let { reserve_id, reserve_lottery } = r; + if (reserve_lottery === 1) { + obj.reserve_id = reserve_id + ""; + obj.reserve_lottery_text = "信息丢失"; + } + } + if (extend_json.match(/"":\{"lottery/)) { + obj.is_charge_lottery = true + } + /* 是否有官方抽奖 */ + obj.hasOfficialLottery = extension && extension.lott && true; + /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ + obj.description = + (item && ((item.content || '') + (item.description || ''))) + || ( + (cardToJson.dynamic || '') + + (cardToJson.desc || '') + + (cardToJson.vest && cardToJson.vest.content || '') + ) + || ''; + /* 转发 */ + if (obj.type === 1) { + const { origin_extension, origin, origin_extend_json = "{}" } = cardToJson + , originToJson = strToJson(origin) + , { add_on_card_info = [] } = display.origin || {} + , originExtendjsonToJson = strToJson(origin_extend_json) + , { user, item } = originToJson; + /* 源动态的ts10 */ + obj.origin_create_time = desc.origin.timestamp; + /* 被转发者的UID */ + obj.origin_uid = desc.origin.uid; + /* 源动态类型 */ + obj.origin_type = desc.orig_type + /* 被转发者的rid(用于发评论) */ + obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; + /* 用于发送评论 */ + obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 + /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ + obj.origin_dynamic_id = desc.orig_dy_id_str; + /* 预约抽奖信息 */ + if (add_on_card_info.length > 0) { + const [status, oid_str, text] = add_on_card_info + .filter(it => typeof it.reserve_attach_card !== 'undefined' + && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' + && typeof it.reserve_attach_card.reserve_button !== 'undefined') + .map(({ reserve_attach_card }) => [ + reserve_attach_card.reserve_button.status, + reserve_attach_card.oid_str, + reserve_attach_card.reserve_lottery.text])[0] || []; + if (status === 1) { + obj.origin_reserve_id = oid_str; + obj.origin_reserve_lottery_text = text; + } + } + if (originExtendjsonToJson[""]) { + let r = originExtendjsonToJson[""].reserve || {}; + let { reserve_id, reserve_lottery } = r; + if (reserve_lottery === 1) { + obj.origin_reserve_id = reserve_id + ""; + obj.origin_reserve_lottery_text = "信息丢失"; + } + } + if (origin_extend_json.match(/"":\{"lottery/)) { + obj.origin_is_charge_lottery = true + } + /* 是否有官方抽奖 */ + obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; + /* 被转发者的name */ + obj.origin_uname = (user && (user.name || user.uname)) || ''; + /* 被转发者的描述 */ + obj.origin_description = + (item && (item.content || '' + item.description || '')) + || (originToJson.dynamic || '' + originToJson.desc || '') + || ''; + } + + return obj +} + /** * 处理来自个人动态或话题页面的一组动态数据 * @param {String} res @@ -197,7 +327,7 @@ function modifyDynamicRes(res) { */ array = next.has_more === 0 ? [] - : cards.map(parseDynamicCard) + : cards.map(oldParseDynamicCard) log.info('处理动态数据', `动态数据读取完毕(${cards.length})(${next.has_more})`); From fc4175032351e60d413c3eeb5505d0a505d57b68 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 3 May 2024 08:52:32 +0800 Subject: [PATCH 32/74] =?UTF-8?q?fix:=20=E6=BA=90rid=5Fstr=E8=8E=B7?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 220 +++++++++++++++++++++----------------- test/article.test.js | 2 +- test/dynamic_card.test.js | 20 ++-- 3 files changed, 133 insertions(+), 109 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 88fa1a7586..c0262710aa 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -69,6 +69,13 @@ function parseDynamicCard(ditem) { ["DYNAMIC_TYPE_AV", 8], ["DYNAMIC_TYPE_ARTICLE", 64] ]); + const dy_type2chat_type = new Map([ + ["DYNAMIC_TYPE_FORWARD", 17], + ["DYNAMIC_TYPE_DRAW", 11], + ["DYNAMIC_TYPE_WORD", 17], + ["DYNAMIC_TYPE_AV", 1], + ["DYNAMIC_TYPE_ARTICLE", 12] + ]); /* 转发者的UID */ obj.uid = ditem?.modules?.module_author?.mid || 0 /* 转发者的name */ @@ -126,9 +133,22 @@ function parseDynamicCard(ditem) { /* 源动态类型 */ obj.origin_type = dy_typeenum2num.get(ditem?.orig?.type) || 0 /* 被转发者的rid(用于发评论) */ - obj.origin_rid_str = ditem?.orig?.basic?.comment_id_str || "" + switch (ditem?.orig?.type) { + case "DYNAMIC_TYPE_DRAW": + obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.draw?.id?.toString() || "" + break; + case "DYNAMIC_TYPE_AV": + obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.archive?.aid || "" + break; + case "DYNAMIC_TYPE_ARTICLE": + obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.article?.id?.toString() || "" + break; + default: + obj.origin_rid_str = ditem?.orig?.id_str || "" + break; + } /* 用于发送评论 */ - obj.origin_chat_type = ditem?.orig?.basic?.comment_type || 0 + obj.origin_chat_type = dy_type2chat_type.get(ditem?.orig?.type) || 0 /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ obj.origin_dynamic_id = ditem?.orig?.id_str || "" /* 预约抽奖信息 */ @@ -165,88 +185,33 @@ function oldParseDynamicCard(dynamic_detail_card) { const { strToJson } = utils; /**临时储存单个动态中的信息 */ let obj = {}; - const { desc, card, extension, extend_json = "{}", display = {} } = dynamic_detail_card - , { is_liked = 1, user_profile = {} } = desc - , { info = {} } = user_profile - , cardToJson = strToJson(card) - , extendjsonToJson = strToJson(extend_json) - , { add_on_card_info = [] } = display - , { item } = cardToJson; - const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); - /* 转发者的UID */ - obj.uid = desc.uid - /* 转发者的name */ - obj.uname = info.uname || '' - /* 动态是否点过赞 */ - obj.is_liked = is_liked > 0 - /* 动态的ts10 */ - obj.create_time = desc.timestamp - /* 动态类型 */ - obj.type = desc.type - /* 用于发送评论 */ - obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; - /* 用于发送评论 */ - obj.chat_type = dy_type2chat_type.get(obj.type) || 0; - /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.dynamic_id = desc.dynamic_id_str; - /* 定位@信息 */ - obj.ctrl = (extendjsonToJson.ctrl) || []; - /* 预约抽奖信息 */ - if (add_on_card_info.length > 0) { - const [status, oid_str, text] = add_on_card_info - .filter(it => typeof it.reserve_attach_card !== 'undefined' - && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' - && typeof it.reserve_attach_card.reserve_button !== 'undefined') - .map(({ reserve_attach_card }) => [ - reserve_attach_card.reserve_button.status, - reserve_attach_card.oid_str, - reserve_attach_card.reserve_lottery.text])[0] || []; - if (status === 1) { - obj.reserve_id = oid_str; - obj.reserve_lottery_text = text; - } - } - if (extendjsonToJson[""]) { - let r = extendjsonToJson[""].reserve || {}; - let { reserve_id, reserve_lottery } = r; - if (reserve_lottery === 1) { - obj.reserve_id = reserve_id + ""; - obj.reserve_lottery_text = "信息丢失"; - } - } - if (extend_json.match(/"":\{"lottery/)) { - obj.is_charge_lottery = true - } - /* 是否有官方抽奖 */ - obj.hasOfficialLottery = extension && extension.lott && true; - /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ - obj.description = - (item && ((item.content || '') + (item.description || ''))) - || ( - (cardToJson.dynamic || '') - + (cardToJson.desc || '') - + (cardToJson.vest && cardToJson.vest.content || '') - ) - || ''; - /* 转发 */ - if (obj.type === 1) { - const { origin_extension, origin, origin_extend_json = "{}" } = cardToJson - , originToJson = strToJson(origin) - , { add_on_card_info = [] } = display.origin || {} - , originExtendjsonToJson = strToJson(origin_extend_json) - , { user, item } = originToJson; - /* 源动态的ts10 */ - obj.origin_create_time = desc.origin.timestamp; - /* 被转发者的UID */ - obj.origin_uid = desc.origin.uid; - /* 源动态类型 */ - obj.origin_type = desc.orig_type - /* 被转发者的rid(用于发评论) */ - obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; + try { + const { desc, card, extension, extend_json = "{}", display = {} } = dynamic_detail_card + , { is_liked = 1, user_profile = {} } = desc + , { info = {} } = user_profile || {} + , cardToJson = strToJson(card) + , extendjsonToJson = strToJson(extend_json) + , { add_on_card_info = [] } = display || {} + , { item } = cardToJson; + const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); + /* 转发者的UID */ + obj.uid = desc.uid + /* 转发者的name */ + obj.uname = info.uname || '' + /* 动态是否点过赞 */ + obj.is_liked = is_liked > 0 + /* 动态的ts10 */ + obj.create_time = desc.timestamp + /* 动态类型 */ + obj.type = desc.type /* 用于发送评论 */ - obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 - /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.origin_dynamic_id = desc.orig_dy_id_str; + obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; + /* 用于发送评论 */ + obj.chat_type = dy_type2chat_type.get(obj.type) || 0; + /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ + obj.dynamic_id = desc.dynamic_id_str; + /* 定位@信息 */ + obj.ctrl = (extendjsonToJson.ctrl) || []; /* 预约抽奖信息 */ if (add_on_card_info.length > 0) { const [status, oid_str, text] = add_on_card_info @@ -258,30 +223,89 @@ function oldParseDynamicCard(dynamic_detail_card) { reserve_attach_card.oid_str, reserve_attach_card.reserve_lottery.text])[0] || []; if (status === 1) { - obj.origin_reserve_id = oid_str; - obj.origin_reserve_lottery_text = text; + obj.reserve_id = oid_str; + obj.reserve_lottery_text = text; } } - if (originExtendjsonToJson[""]) { - let r = originExtendjsonToJson[""].reserve || {}; + if (extendjsonToJson[""]) { + let r = extendjsonToJson[""].reserve || {}; let { reserve_id, reserve_lottery } = r; if (reserve_lottery === 1) { - obj.origin_reserve_id = reserve_id + ""; - obj.origin_reserve_lottery_text = "信息丢失"; + obj.reserve_id = reserve_id + ""; + obj.reserve_lottery_text = "信息丢失"; } } - if (origin_extend_json.match(/"":\{"lottery/)) { - obj.origin_is_charge_lottery = true + if (extend_json.match(/"":\{"lottery/)) { + obj.is_charge_lottery = true } /* 是否有官方抽奖 */ - obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; - /* 被转发者的name */ - obj.origin_uname = (user && (user.name || user.uname)) || ''; - /* 被转发者的描述 */ - obj.origin_description = - (item && (item.content || '' + item.description || '')) - || (originToJson.dynamic || '' + originToJson.desc || '') + obj.hasOfficialLottery = extension && extension.lott && true; + /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ + obj.description = + (item && ((item.content || '') + (item.description || ''))) + || ( + (cardToJson.dynamic || '') + + (cardToJson.desc || '') + + (cardToJson.vest && cardToJson.vest.content || '') + ) || ''; + /* 转发 */ + if (obj.type === 1) { + const { origin_extension, origin, origin_extend_json = "{}" } = cardToJson + , originToJson = strToJson(origin) + , { add_on_card_info = [] } = display.origin || {} + , originExtendjsonToJson = strToJson(origin_extend_json) + , { user, item } = originToJson; + /* 源动态的ts10 */ + obj.origin_create_time = desc.origin.timestamp; + /* 被转发者的UID */ + obj.origin_uid = desc.origin.uid; + /* 源动态类型 */ + obj.origin_type = desc.orig_type + /* 被转发者的rid(用于发评论) */ + obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; + /* 用于发送评论 */ + obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 + /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ + obj.origin_dynamic_id = desc.orig_dy_id_str; + /* 预约抽奖信息 */ + if (add_on_card_info.length > 0) { + const [status, oid_str, text] = add_on_card_info + .filter(it => typeof it.reserve_attach_card !== 'undefined' + && typeof it.reserve_attach_card.reserve_lottery !== 'undefined' + && typeof it.reserve_attach_card.reserve_button !== 'undefined') + .map(({ reserve_attach_card }) => [ + reserve_attach_card.reserve_button.status, + reserve_attach_card.oid_str, + reserve_attach_card.reserve_lottery.text])[0] || []; + if (status === 1) { + obj.origin_reserve_id = oid_str; + obj.origin_reserve_lottery_text = text; + } + } + if (originExtendjsonToJson[""]) { + let r = originExtendjsonToJson[""].reserve || {}; + let { reserve_id, reserve_lottery } = r; + if (reserve_lottery === 1) { + obj.origin_reserve_id = reserve_id + ""; + obj.origin_reserve_lottery_text = "信息丢失"; + } + } + if (origin_extend_json.match(/"":\{"lottery/)) { + obj.origin_is_charge_lottery = true + } + /* 是否有官方抽奖 */ + obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; + /* 被转发者的name */ + obj.origin_uname = (user && (user.name || user.uname)) || ''; + /* 被转发者的描述 */ + obj.origin_description = + (item && (item.content || '' + item.description || '')) + || (originToJson.dynamic || '' + originToJson.desc || '') + || ''; + } + } catch (e) { + log.error("动态卡片解析", e) } return obj diff --git a/test/article.test.js b/test/article.test.js index a43b39854a..e0691e608f 100644 --- a/test/article.test.js +++ b/test/article.test.js @@ -3,7 +3,7 @@ const bili_client = require("../lib/net/bili"); const util = require('./util'); (async () => { - await util.par_run([0], [ + await util.par_run([], [ // 0 async () => { let info = await bili_client.getOneArticleByCv(22112353); diff --git a/test/dynamic_card.test.js b/test/dynamic_card.test.js index e655464b56..3fa7ea074d 100644 --- a/test/dynamic_card.test.js +++ b/test/dynamic_card.test.js @@ -4,7 +4,7 @@ const searcher = require("../lib/core/searcher"); const util = require('./util'); (async () => { - await util.par_run([0, 1, 2, 3, 4, 5, 6, 7, 8], [ + await util.par_run([3], [ // 0 async () => { let info = await bili_client.getOneDynamicByDyid("728424890210713624"); @@ -23,11 +23,11 @@ const util = require('./util'); }, // 3 async () => { - let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("747169355882561625")); - assert(card.chat_type == 11) - card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("747441158580338693")); - assert(card.chat_type == 17) - assert(card.origin_chat_type == 11) + let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("900172162530279445")); + assert.equal(card.chat_type, 11) + card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("926978638295859236")); + assert.equal(card.chat_type, 17) + assert.equal(card.origin_chat_type, 11) }, // 4 async () => { @@ -52,15 +52,15 @@ const util = require('./util'); }, // 7 async () => { - const dy = await bili_client.getOneDynamicByDyid("832208853440397352"); + const dy = await bili_client.getOneDynamicByDyid("924676093465591832"); const card = searcher.parseDynamicCard(dy) - assert.equal(card.reserve_id, "3106984"); + assert.equal(card.reserve_id, "3715576"); }, // 8 async () => { - const dy = await bili_client.getOneDynamicByDyid("832966468497834066"); + const dy = await bili_client.getOneDynamicByDyid("925061227481137187"); const card = searcher.parseDynamicCard(dy) - assert.equal(card.origin_reserve_id, "3106984"); + assert.equal(card.origin_reserve_id, "3715576"); }, ]) From 1e7d8b2370e5d1a801feffb20964fea36c1c31f3 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 3 May 2024 09:28:22 +0800 Subject: [PATCH 33/74] =?UTF-8?q?feat:=20=E5=8A=A8=E6=80=81=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E6=96=B0=E8=80=81api=E5=85=B1=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 8 ++++++-- lib/net/api.bili.js | 3 ++- lib/net/bili.js | 17 +++++++++-------- test/dynamic_card.test.js | 8 ++++---- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index c0262710aa..e00ee5e97b 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -55,10 +55,14 @@ const { log } = utils * @property {number} type * @property {boolean} hasOfficialLottery 是否官方 * - * @param {object} ditem + * @param {object} data * @return {UsefulDynamicInfo} */ -function parseDynamicCard(ditem) { +function parseDynamicCard(data) { + if (data?.card?.desc?.uid) { + return oldParseDynamicCard(data?.card) + } + let ditem = data?.item; /**临时储存单个动态中的信息 */ let obj = {}; try { diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index 245240b554..f93f8ff665 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -5,7 +5,7 @@ module.exports = Object.freeze({ DYNAMIC_REPOST_SHARE: 'https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/share', DYNAMIC_SVR_CREATE_DRAW: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create_draw', DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', - X_POLYMER_WEB_DYNAMIC_V1_DETAIL: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/detail', + DYNAMIC_SVR_GET_DYNAMIC_DETAIL: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', @@ -38,4 +38,5 @@ module.exports = Object.freeze({ WEB_INTERFACE_CARD: 'https://api.bilibili.com/x/web-interface/card', WEB_INTERFACE_NAV_STAT: "https://api.bilibili.com/x/web-interface/nav/stat", WEB_INTERFACE_SEARCH_TYPE: 'https://api.bilibili.com/x/web-interface/search/type', + X_POLYMER_WEB_DYNAMIC_V1_DETAIL: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/detail', }) diff --git a/lib/net/bili.js b/lib/net/bili.js index d824ff8417..261da42fac 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -422,20 +422,21 @@ const bili_client = { id } }), + (dynamic_id) => get({ + url: API.DYNAMIC_SVR_GET_DYNAMIC_DETAIL, + config: { retry: false }, + query: { + dynamic_id + } + }), ] , responseText => { const res = strToJson(responseText), - { code, data } = res, - { item } = data || {}, - { id_str } = item || {}; + { code, data } = res; switch (code) { case 0: - if (item && id_str) { - return [false, item, `ok`]; - } else { - return [false, undefined, `获取动态数据异常:\n${responseText}`]; - } + return [false, data, `ok`]; default: return [true, undefined, `获取动态数据出错:\n${responseText}`] } diff --git a/test/dynamic_card.test.js b/test/dynamic_card.test.js index 3fa7ea074d..aec1dd263d 100644 --- a/test/dynamic_card.test.js +++ b/test/dynamic_card.test.js @@ -4,7 +4,7 @@ const searcher = require("../lib/core/searcher"); const util = require('./util'); (async () => { - await util.par_run([3], [ + await util.par_run([0, 1, 2, 3, 4, 5, 6, 7, 8], [ // 0 async () => { let info = await bili_client.getOneDynamicByDyid("728424890210713624"); @@ -31,9 +31,9 @@ const util = require('./util'); }, // 4 async () => { - assert.equal(await bili_client.getOneDynamicByDyid("111111111111111111"), undefined); - assert.notEqual(await bili_client.getOneDynamicByDyid("746824225190314008"), undefined); - assert.equal(await bili_client.getOneDynamicByDyid("761475750233636886"), undefined); + // assert.equal(await bili_client.getOneDynamicByDyid("111111111111111111"), undefined); + // assert.notEqual(await bili_client.getOneDynamicByDyid("746824225190314008"), undefined); + // assert.equal(await bili_client.getOneDynamicByDyid("761475750233636886"), undefined); }, // 5 async () => { From 9f417d669de27dadc9eefd393c8f03ca4f90bad2 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 3 May 2024 09:29:03 +0800 Subject: [PATCH 34/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- script/build/changelog.sh | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 364db030a9..ee07320aa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # CHANGELOG +## 主要变化(2.9.0) +* 1e7d8b2 feat: 动态详情新老api共存 +* fc41750 fix: 源rid_str获取 +* 1a08c0a fix: 话题uid动态获取使用老解析函数 +* 666c057 feat: 使用新接口替换动态详情老接口 (#382) +* df3e97d ci: fix "an artifact with this name already exists on the workflow run" + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.8.19) * d9f6bf2 feat: 中奖检测屏蔽自动回复 (#381) * ded981e fix: 动态卡片解析出错导致程序停止 diff --git a/package.json b/package.json index 8e72c14871..981e98119e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.8.19", + "version": "2.9.0", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { diff --git a/script/build/changelog.sh b/script/build/changelog.sh index b2a6ec6905..88045f5428 100644 --- a/script/build/changelog.sh +++ b/script/build/changelog.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # version: -level=patch +level=minor npm version $level \ --no-commit-hooks \ From e72313694a359af1a3d99091cb4a31414161a792 Mon Sep 17 00:00:00 2001 From: shanmite Date: Thu, 13 Jun 2024 17:19:53 +0800 Subject: [PATCH 35/74] =?UTF-8?q?feat:=20=20=E5=8F=AF=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E9=AA=8C=E8=AF=81=E7=A0=81=E8=AF=86=E5=88=ABAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #395 --- env.example.js | 4 +++- lib/utils.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/env.example.js b/env.example.js index 7deafe1eb0..7cba177b6d 100644 --- a/env.example.js +++ b/env.example.js @@ -8,6 +8,7 @@ module.exports = Object.freeze({ * - `ACCOUNT_UA` 账号UA, 可在浏览器控制台输入 navigator.userAgent 查看 * ## 高级功能 * - `ENABLE_CHAT_CAPTCHA_OCR` 开启评论验证码识别 使用方法见README + * - `CHAT_CAPTCHA_OCR_URL` 验证码识别接口 POST `url`->`code` * - `ENABLE_MULTIPLE_ACCOUNT` 是否启用多账号 * - `MULTIPLE_ACCOUNT_PARM` 多账号参数(JSON格式) <不推荐使用 * ## 调试相关 @@ -28,7 +29,8 @@ module.exports = Object.freeze({ CLEAR: true, ACCOUNT_UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", - ENABLE_CHAT_CAPTCHA_OCR: "", + ENABLE_CHAT_CAPTCHA_OCR: false, + CHAT_CAPTCHA_OCR_URL: "http://127.0.0.1:9898/ocr/url/text", ENABLE_MULTIPLE_ACCOUNT: false, MULTIPLE_ACCOUNT_PARM: "", diff --git a/lib/utils.js b/lib/utils.js index 54fcf60c31..d32d4fdfed 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -287,7 +287,7 @@ const utils = { return new Promise((resolve) => { send({ method: 'POST', - url: 'http://127.0.0.1:9898/ocr/url/text', + url: process.env["CHAT_CAPTCHA_OCR_URL"] || "http://127.0.0.1:9898/ocr/url/text", headers: { "content-type": 'application/x-www-form-urlencoded; charset=UTF-8', }, From 6c75d57adbd19fbc4755540772db87775f83a37c Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 21 Jun 2024 16:55:12 +0800 Subject: [PATCH 36/74] lint: eslint --- .eslintrc.json | 10 +- env.example.js | 76 ++++----- lib/account.js | 12 +- lib/check.js | 74 ++++----- lib/clear.js | 56 +++---- lib/core/monitor.js | 298 +++++++++++++++++------------------ lib/core/searcher.js | 306 ++++++++++++++++++------------------ lib/data/config.js | 26 +-- lib/data/env.js | 18 +-- lib/data/global_var.js | 46 +++--- lib/helper/d_storage.js | 32 ++-- lib/helper/event_bus.js | 4 +- lib/helper/notify.js | 248 ++++++++++++++--------------- lib/helper/randomDynamic.js | 24 +-- lib/index.js | 14 +- lib/login.js | 18 +-- lib/lottery.js | 14 +- lib/net/api.bili.js | 10 +- lib/net/bili.js | 230 +++++++++++++-------------- lib/net/http.js | 48 +++--- lib/update.js | 54 +++---- lib/utils.js | 166 +++++++++---------- main.js | 86 +++++----- my_config.example.js | 24 +-- package.json | 4 +- test/api.test.js | 32 ++-- test/article.test.js | 10 +- test/dynamic_card.test.js | 60 +++---- test/index.js | 14 +- test/ocr.test.js | 8 +- test/util.js | 4 +- 31 files changed, 1018 insertions(+), 1008 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 3a28b3ef20..339d795e7b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,5 +9,13 @@ "ecmaVersion": "latest" }, "rules": { + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] } -} +} \ No newline at end of file diff --git a/env.example.js b/env.example.js index 7cba177b6d..f237ed1e75 100644 --- a/env.example.js +++ b/env.example.js @@ -23,19 +23,19 @@ module.exports = Object.freeze({ * **按顺序依次执行, 防止访问频繁封禁IP** */ account_parm: { - COOKIE: "", - NOTE: "", + COOKIE: '', + NOTE: '', NUMBER: 1, CLEAR: true, - ACCOUNT_UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", + ACCOUNT_UA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', ENABLE_CHAT_CAPTCHA_OCR: false, - CHAT_CAPTCHA_OCR_URL: "http://127.0.0.1:9898/ocr/url/text", + CHAT_CAPTCHA_OCR_URL: 'http://127.0.0.1:9898/ocr/url/text', ENABLE_MULTIPLE_ACCOUNT: false, - MULTIPLE_ACCOUNT_PARM: "", + MULTIPLE_ACCOUNT_PARM: '', LOTTERY_LOG_LEVEL: 3, - NOT_GO_LOTTERY: "" + NOT_GO_LOTTERY: '' }, /** @@ -59,12 +59,12 @@ module.exports = Object.freeze({ */ multiple_account_parm: [ { - COOKIE: "", - NOTE: "", + COOKIE: '', + NOTE: '', NUMBER: 1, CLEAR: true, WAIT: 60 * 1000, - ACCOUNT_UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" + ACCOUNT_UA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36' } ], @@ -72,33 +72,33 @@ module.exports = Object.freeze({ * 推送相关参数 */ push_parm: { - SCKEY: "", - SENDKEY: "", - QQ_SKEY: "", - QQ_MODE: "", - BARK_PUSH: "", - BARK_SOUND: "", - PUSHDEER_URL: "", - PUSHDEER_PUSHKEY: "", - TG_BOT_TOKEN: "", - TG_USER_ID: "", - TG_PROXY_HOST: "", - TG_PROXY_PORT: "", - DD_BOT_TOKEN: "", - DD_BOT_SECRET: "", - QYWX_AM: "", - QYWX_KEY: "", - IGOT_PUSH_KEY: "", - PUSH_PLUS_TOKEN: "", - PUSH_PLUS_USER: "", - QMSG_KEY: "", - QMSG_QQ: "", - SMTP_HOST: "", - SMTP_PORT: "", - SMTP_USER: "", - SMTP_PASS: "", - SMTP_TO_USER: "", - GOTIFY_URL: "", - GOTIFY_APPKEY: "" + SCKEY: '', + SENDKEY: '', + QQ_SKEY: '', + QQ_MODE: '', + BARK_PUSH: '', + BARK_SOUND: '', + PUSHDEER_URL: '', + PUSHDEER_PUSHKEY: '', + TG_BOT_TOKEN: '', + TG_USER_ID: '', + TG_PROXY_HOST: '', + TG_PROXY_PORT: '', + DD_BOT_TOKEN: '', + DD_BOT_SECRET: '', + QYWX_AM: '', + QYWX_KEY: '', + IGOT_PUSH_KEY: '', + PUSH_PLUS_TOKEN: '', + PUSH_PLUS_USER: '', + QMSG_KEY: '', + QMSG_QQ: '', + SMTP_HOST: '', + SMTP_PORT: '', + SMTP_USER: '', + SMTP_PASS: '', + SMTP_TO_USER: '', + GOTIFY_URL: '', + GOTIFY_APPKEY: '' } -}) +}); diff --git a/lib/account.js b/lib/account.js index f7b8d11d16..c7f81d4e4d 100644 --- a/lib/account.js +++ b/lib/account.js @@ -1,15 +1,15 @@ -const bili = require('./net/bili') -const { log } = require('./utils') +const bili = require('./net/bili'); +const { log } = require('./utils'); async function account() { const my_info = await bili.getMyinfo(); const stat = await bili.getStat(); if (my_info && stat) { - log.info("帐号信息", `${my_info.name} Lv${my_info.level} ${my_info.silence ? "已封禁" : "未封禁"} 升级还需${my_info.level_exp.next_exp - my_info.level_exp.current_exp}经验`) - log.info("帐号信息", `当前关注数:${stat.following} 粉丝数:${stat.follower} 动态数量:${stat.dynamic_count}`) + log.info('帐号信息', `${my_info.name} Lv${my_info.level} ${my_info.silence ? '已封禁' : '未封禁'} 升级还需${my_info.level_exp.next_exp - my_info.level_exp.current_exp}经验`); + log.info('帐号信息', `当前关注数:${stat.following} 粉丝数:${stat.follower} 动态数量:${stat.dynamic_count}`); } else { - log.error("帐号信息", "获取失败"); + log.error('帐号信息', '获取失败'); } } -module.exports = { account } \ No newline at end of file +module.exports = { account }; \ No newline at end of file diff --git a/lib/check.js b/lib/check.js index 853fde8253..ba7e73a39d 100644 --- a/lib/check.js +++ b/lib/check.js @@ -1,8 +1,8 @@ -const { log, delay, infiniteNumber, judge } = require('./utils') -const { sendNotify } = require('./helper/notify') -const config = require('./data/config') -const global_var = require('./data/global_var') -const bili = require('./net/bili') +const { log, delay, infiniteNumber, judge } = require('./utils'); +const { sendNotify } = require('./helper/notify'); +const config = require('./data/config'); +const global_var = require('./data/global_var'); +const bili = require('./net/bili'); /** * 是否中奖 @@ -21,14 +21,14 @@ async function isMe(num) { MyAtInfo .slice(0, unread_at_num) .forEach(({ at_time, up_uname, business, source_content, url }) => { - desp += '## [at]检测结果\n\n' - desp += '- - - -\n\n' - desp += `发生时间: ${new Date(at_time * 1000).toLocaleString()}\n\n` - desp += `用户: ${up_uname}\n\n` - desp += `在${business}中@了[你](https://space.bilibili.com/${global_var.get("myUID")})\n\n` - desp += `原内容为: ${source_content}\n\n` - desp += `[直达链接](${url})\n\n` - desp += '- - - -\n\n' + desp += '## [at]检测结果\n\n'; + desp += '- - - -\n\n'; + desp += `发生时间: ${new Date(at_time * 1000).toLocaleString()}\n\n`; + desp += `用户: ${up_uname}\n\n`; + desp += `在${business}中@了[你](https://space.bilibili.com/${global_var.get('myUID')})\n\n`; + desp += `原内容为: ${source_content}\n\n`; + desp += `[直达链接](${url})\n\n`; + desp += '- - - -\n\n'; }); log.info('中奖检测', '--> OK'); } @@ -39,22 +39,22 @@ async function isMe(num) { .slice(0, unread_reply_num) .forEach(({ nickname, uri, source, timestamp }) => { if (judge(source, notice_key_words)) { - desp += '## 回复检测结果\n\n' - desp += '- - - -\n\n' - desp += `发生时间: ${new Date(timestamp * 1000).toLocaleString()}\n\n` - desp += `用户: ${nickname}\n\n` - desp += `回复[你](https://space.bilibili.com/${global_var.get("myUID")})说:\n${source}\n\n` - desp += `[直达链接](${uri})\n\n` - desp += '- - - -\n\n' + desp += '## 回复检测结果\n\n'; + desp += '- - - -\n\n'; + desp += `发生时间: ${new Date(timestamp * 1000).toLocaleString()}\n\n`; + desp += `用户: ${nickname}\n\n`; + desp += `回复[你](https://space.bilibili.com/${global_var.get('myUID')})说:\n${source}\n\n`; + desp += `[直达链接](${uri})\n\n`; + desp += '- - - -\n\n'; } - }) + }); log.info('中奖检测', '--> OK'); } if (follow_unread + unfollow_unread > 0) { const check = async (type) => { let session_t = ''; - let MySession = await bili.getSessionInfo(type) - log.info("准备检查私信", check_session_pages + "页") + let MySession = await bili.getSessionInfo(type); + log.info('准备检查私信', check_session_pages + '页'); for (const index of infiniteNumber()) { for (const Session of MySession.data) { const { sender_uid, session_ts, timestamp, unread_count, talker_id, msg_seqno } = Session; @@ -62,13 +62,13 @@ async function isMe(num) { if (unread_count) { const content = await bili.fetch_session_msgs(talker_id, unread_count); if (judge(content, notice_key_words)) { - desp += '## 私信检测结果\n\n' - desp += '- - - -\n\n' - desp += `发生时间: ${new Date(timestamp * 1000).toLocaleString()}\n\n` - desp += `用户: ${sender_uid}\n\n` - desp += `私信[你](https://space.bilibili.com/${global_var.get("myUID")})说:\n${content}\n\n` - desp += `[直达链接](https://message.bilibili.com/#/whisper/mid${sender_uid})\n\n` - desp += '- - - -\n\n' + desp += '## 私信检测结果\n\n'; + desp += '- - - -\n\n'; + desp += `发生时间: ${new Date(timestamp * 1000).toLocaleString()}\n\n`; + desp += `用户: ${sender_uid}\n\n`; + desp += `私信[你](https://space.bilibili.com/${global_var.get('myUID')})说:\n${content}\n\n`; + desp += `[直达链接](https://message.bilibili.com/#/whisper/mid${sender_uid})\n\n`; + desp += '- - - -\n\n'; } await bili.updateSessionStatus(talker_id, type, msg_seqno); await delay(update_session_wait); @@ -76,26 +76,26 @@ async function isMe(num) { } if (MySession.has_more && index < check_session_pages) { await delay(get_session_wait); - MySession = await bili.getSessionInfo(type, session_t) + MySession = await bili.getSessionInfo(type, session_t); } else { - break + break; } } - } + }; if (follow_unread) { - log.info('中奖检测', '<-- 正在检查已关注者的私信') + log.info('中奖检测', '<-- 正在检查已关注者的私信'); } if (unfollow_unread) { - log.info('中奖检测', '<-- 正在检查未关注者的私信') + log.info('中奖检测', '<-- 正在检查未关注者的私信'); } - await check("1") + await check('1'); log.info('中奖检测', '--> OK'); } if (desp) { log.info('可能中奖了', desp); await sendNotify(`帐号${num}可能中奖了`, desp); } else { - log.info('中奖检测', "暂未中奖"); + log.info('中奖检测', '暂未中奖'); } return; } diff --git a/lib/clear.js b/lib/clear.js index 882dcbc9a7..2b7b4c1530 100644 --- a/lib/clear.js +++ b/lib/clear.js @@ -1,8 +1,8 @@ -const { log, delay, infiniteNumber, retryfn } = require("./utils"); -const bili = require("./net/bili"); -const { Searcher } = require("./core/searcher"); +const { log, delay, infiniteNumber, retryfn } = require('./utils'); +const bili = require('./net/bili'); +const { Searcher } = require('./core/searcher'); const global_var = require('./data/global_var'); -const config = require("./data/config"); +const config = require('./data/config'); /** * 获取关注分区里的uid @@ -16,13 +16,13 @@ async function getFollowList(partition) { let rmup = []; if (typeof tagid === 'undefined') { log.info('获取关注列表', '未能成功获取关注分区id'); - return rmup + return rmup; } for (let index = 1; index < 100; index++) { const uids = await bili.getPartitionUID(tagid, index); await delay(get_partition_wait); if (!uids.length) break; - rmup.push(...uids) + rmup.push(...uids); } return clear_white_list.length ? rmup.filter(uid => clear_white_list.split(',').indexOf(String(uid)) === -1) @@ -37,24 +37,24 @@ async function clear() { let success = true; const uid_list = (await Promise.all(clear_partition.split(',').map(getFollowList))).flat(); if (!uid_list.length) { - log.info('清理关注', `关注为空`) + log.info('清理关注', '关注为空'); } else { - log.info('清理关注', `共有${uid_list.length}个关注`) + log.info('清理关注', `共有${uid_list.length}个关注`); } if (clear_quick_remove_attention) { - log.info('清理关注', '进入只清理关注模式') + log.info('清理关注', '进入只清理关注模式'); /* 专清关注 */ for (const [index, uid] of uid_list.entries()) { const fannumber = await bili.getUserInfo(uid); - log.info('清理关注', `粉丝数${fannumber}`) + log.info('清理关注', `粉丝数${fannumber}`); if (fannumber !== -1 && fannumber < clear_quick_remove_attention_fans_number_smallest) { - log.info('清理关注', `(${index}) (${uid})`) + log.info('清理关注', `(${index}) (${uid})`); /* 取消关注 */ if (await retryfn(3, [false], () => bili.cancelAttention(uid))) { - log.info('清理关注', '成功') + log.info('清理关注', '成功'); } else { - log.error('清理关注', '失败') - break + log.error('清理关注', '失败'); + break; } } /* 延时 */ @@ -77,7 +77,7 @@ async function clear() { )) || { allModifyDynamicResArray: [], offset: '0' }; next_offset = offset; for (const [index, dyinfo] of allModifyDynamicResArray.entries()) { - log.info('清理动态', `第${page + 1}页中的第${index + 1}个动态`) + log.info('清理动态', `第${page + 1}页中的第${index + 1}个动态`); const { type, dynamic_id, create_time, origin_uid } = dyinfo || {}; if (typeof type !== 'undefined' && clear_dynamic_type instanceof Array @@ -87,12 +87,12 @@ async function clear() { const days_ago = (Now - create_time) / 86400; if (days_ago > clear_max_day) { - log.debug('清理动态', `当前UID保护列表:\n${before_separate.join(',')}\n`) + log.debug('清理动态', `当前UID保护列表:\n${before_separate.join(',')}\n`); /* 移除动态 */ if (dynamic_id && clear_remove_dynamic && !(new RegExp(dynamic_id).test(clear_white_list))) { - success = await retryfn(3, [false], () => bili.rmDynamic(dynamic_id)) + success = await retryfn(3, [false], () => bili.rmDynamic(dynamic_id)); } /* 取消关注 */ @@ -101,38 +101,38 @@ async function clear() { && clear_remove_attention && before_separate.indexOf(origin_uid) === -1 && uid_list.indexOf(origin_uid) > -1) { - success = await retryfn(3, [false], () => bili.cancelAttention(origin_uid)) + success = await retryfn(3, [false], () => bili.cancelAttention(origin_uid)); } if (!success) { - log.error("清理失败", "出现错误") - break + log.error('清理失败', '出现错误'); + break; } /* 延时 */ await delay(clear_remove_delay); } else { - log.info('清理动态', `已设置跳过${clear_max_day}天 当前动态(${dynamic_id})发布时间: ${~~days_ago}天前`) + log.info('清理动态', `已设置跳过${clear_max_day}天 当前动态(${dynamic_id})发布时间: ${~~days_ago}天前`); if (origin_uid) { - log.info('清理动态', `储存用户(${origin_uid})防止误删`) - before_separate.push(origin_uid) + log.info('清理动态', `储存用户(${origin_uid})防止误删`); + before_separate.push(origin_uid); } else { - log.info('清理动态', `非转发动态`) + log.info('清理动态', '非转发动态'); } } } else { - log.info('清理动态', `此动态类型为${type} != 要清理的动态类型${clear_dynamic_type}`) + log.info('清理动态', `此动态类型为${type} != 要清理的动态类型${clear_dynamic_type}`); } } /* 延时 */ await delay(clear_remove_delay); - log.info('清理动态', `第${page + 1}页(${allModifyDynamicResArray.length})中的转发动态与关注全部处理成功`) + log.info('清理动态', `第${page + 1}页(${allModifyDynamicResArray.length})中的转发动态与关注全部处理成功`); if (next_offset === '0' || !success) break; } } - return + return; } -module.exports = { clear } +module.exports = { clear }; diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 61d19db061..ad44b2a4c5 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -3,10 +3,10 @@ const { send } = require('../net/http'); const bili = require('../net/bili'); const { sendNotify } = require('../helper/notify'); const event_bus = require('../helper/event_bus'); -const { randomDynamic } = require('../helper/randomDynamic') +const { randomDynamic } = require('../helper/randomDynamic'); const { Searcher } = require('./searcher'); -const global_var = require("../data/global_var"); -const config = require("../data/config"); +const global_var = require('../data/global_var'); +const config = require('../data/config'); const d_storage = require('../helper/d_storage'); /** @@ -19,7 +19,7 @@ class Monitor extends Searcher { */ constructor(lottery_param) { super(); - this.lottery_param = lottery_param + this.lottery_param = lottery_param; this.tagid = config.partition_id; /* tagid初始化 */ this.attentionList = ''; /* 转为字符串的所有关注的up主uid */ this.LotteryInfoMap = new Map([ @@ -35,68 +35,68 @@ class Monitor extends Searcher { */ async init() { if (config.model === '00') { - event_bus.emit('Turn_off_the_Monitor', '已关闭所有转发行为') - return + event_bus.emit('Turn_off_the_Monitor', '已关闭所有转发行为'); + return; } if (!this.tagid && config.is_not_create_partition !== true) { - this.tagid = await bili.checkMyPartition() /* 检查关注分区 */ + this.tagid = await bili.checkMyPartition(); /* 检查关注分区 */ if (!this.tagid) { - event_bus.emit('Turn_off_the_Monitor', '分区获取失败') - return + event_bus.emit('Turn_off_the_Monitor', '分区获取失败'); + return; } } /** 关注列表初始化 */ - this.attentionList = await bili.getAttentionList(global_var.get("myUID")); + this.attentionList = await bili.getAttentionList(global_var.get('myUID')); const status = await this.startLottery(); switch (status) { case 0: - event_bus.emit('Turn_on_the_Monitor') + event_bus.emit('Turn_on_the_Monitor'); break; case 1001: - event_bus.emit('Turn_off_the_Monitor', '评论失败') + event_bus.emit('Turn_off_the_Monitor', '评论失败'); break; case 1010: - event_bus.emit('Turn_off_the_Monitor', '已掉号') + event_bus.emit('Turn_off_the_Monitor', '已掉号'); break; case 1004: - event_bus.emit('Turn_off_the_Monitor', '需要输入验证码') - break + event_bus.emit('Turn_off_the_Monitor', '需要输入验证码'); + break; case 2001: - event_bus.emit('Turn_off_the_Monitor', '关注出错') + event_bus.emit('Turn_off_the_Monitor', '关注出错'); break; case 3001: - event_bus.emit('Turn_off_the_Monitor', '分区移动出错 可于设置处关闭移动分区') + event_bus.emit('Turn_off_the_Monitor', '分区移动出错 可于设置处关闭移动分区'); break; case 2004: case 4005: - log.warn(`账号异常${status}`, `UID(${global_var.get('myUID')})异常号只会对部分UP出现异常`) + log.warn(`账号异常${status}`, `UID(${global_var.get('myUID')})异常号只会对部分UP出现异常`); if (!config.is_exception) { await sendNotify( `[动态抽奖]账号异常${status}通知`, `UID: ${global_var.get('myUID')}\n异常号只会对部分UP出现异常\n可在设置中令is_exception为true关闭此推送\n${log._cache.filter(it => /Error|\s抽奖信息\]/.test(it)).join('\n')}` - ) + ); } config.is_exception = true; - event_bus.emit('Turn_on_the_Monitor') - break + event_bus.emit('Turn_on_the_Monitor'); + break; case 2005: - log.warn('关注已达上限', `UID(${global_var.get('myUID')})关注已达上限,已临时进入只转已关注模式`) + log.warn('关注已达上限', `UID(${global_var.get('myUID')})关注已达上限,已临时进入只转已关注模式`); if (!config.is_outof_maxfollow) { await sendNotify( '[动态抽奖]关注已达上限', `UID: ${global_var.get('myUID')}\n关注已达上限,已临时进入只转已关注模式\n可在设置中令is_outof_maxfollow为true关闭此推送\n${log._cache.filter(it => /Error|\s抽奖信息\]/.test(it)).join('\n')}` - ) + ); } config.is_outof_maxfollow = true; config.only_followed = true; - event_bus.emit('Turn_on_the_Monitor') - break + event_bus.emit('Turn_on_the_Monitor'); + break; case 5001: - event_bus.emit('Turn_off_the_Monitor', '转发失败') - break + event_bus.emit('Turn_off_the_Monitor', '转发失败'); + break; default: - event_bus.emit('Turn_off_the_Monitor', `??? 未知错误: ${status}`) + event_bus.emit('Turn_off_the_Monitor', `??? 未知错误: ${status}`); break; } } @@ -126,53 +126,53 @@ class Monitor extends Searcher { && lottery.uid.length && (new RegExp(lottery.uid.join('|'))).test(this.attentionList) ) { - log.info('过滤', `已关注(${lottery.uid.join(',')})`) - continue + log.info('过滤', `已关注(${lottery.uid.join(',')})`); + continue; } if (lottery.isOfficialLottery) { let { ts } = await bili.getLotteryNotice(lottery.dyid); const ts_10 = Date.now() / 1000; if (ts === -1) { - log.warn('过滤', '无法判断开奖时间') - await delay(filter_wait) - continue + log.warn('过滤', '无法判断开奖时间'); + await delay(filter_wait); + continue; } if (ts === -9999) { - log.info('过滤', '已撤销抽奖') - d_storage.updateDyid(lottery.dyid) - await delay(filter_wait) - continue + log.info('过滤', '已撤销抽奖'); + d_storage.updateDyid(lottery.dyid); + await delay(filter_wait); + continue; } if (ts < ts_10) { - log.info('过滤', '已过开奖时间') - d_storage.updateDyid(lottery.dyid) - await delay(filter_wait) - continue + log.info('过滤', '已过开奖时间'); + d_storage.updateDyid(lottery.dyid); + await delay(filter_wait); + continue; } if (ts > ts_10 + config.maxday * 86400) { - log.info('过滤', '超过指定开奖时间') - d_storage.updateDyid(lottery.dyid) - await delay(filter_wait) - continue + log.info('过滤', '超过指定开奖时间'); + d_storage.updateDyid(lottery.dyid); + await delay(filter_wait); + continue; } } else if (lottery.uid[0]) { - const { minfollower } = config + const { minfollower } = config; if (minfollower > 0) { const followerNum = await bili.getUserInfo(lottery.uid[0]); if (followerNum === -1) { - log.warn('过滤', `粉丝数(${followerNum})获取失败`) - await delay(filter_wait) - continue + log.warn('过滤', `粉丝数(${followerNum})获取失败`); + await delay(filter_wait); + continue; } if (followerNum < minfollower) { - log.info('过滤', `粉丝数(${followerNum})小于指定数量`) - d_storage.updateDyid(lottery.dyid) - await delay(filter_wait) - continue + log.info('过滤', `粉丝数(${followerNum})小于指定数量`); + d_storage.updateDyid(lottery.dyid); + await delay(filter_wait); + continue; } } else { - log.info('过滤', "不过滤粉丝数") + log.info('过滤', '不过滤粉丝数'); } } @@ -182,13 +182,13 @@ class Monitor extends Searcher { && index % getRandomOne(create_dy_mode[0]) === 0 ) { const number = getRandomOne(create_dy_mode[1]) || 0; - randomDynamic(number) + randomDynamic(number); } - status = await this.go(lottery) + status = await this.go(lottery); switch (status) { case 0: - relayed_nums += 1 + relayed_nums += 1; break; case 1002: case 1003: @@ -207,16 +207,16 @@ class Monitor extends Searcher { case 5002: case 5003: case 5004: - status = 0 + status = 0; break; case 2004: - is_exception = 2004 + is_exception = 2004; break; case 4005: - is_exception = 4005 + is_exception = 4005; break; case 2005: - is_outof_maxfollow = 2005 + is_outof_maxfollow = 2005; break; case 1001: case 1010: @@ -224,25 +224,25 @@ class Monitor extends Searcher { case 2001: case 3001: case 5001: - is_shutdown = true + is_shutdown = true; break; default: break; } - if (is_shutdown) break + if (is_shutdown) break; - d_storage.updateDyid(lottery.dyid) + d_storage.updateDyid(lottery.dyid); await delay(wait * (Math.random() + 0.5)); } log.info('抽奖', `本轮共处理${total_nums}条,成功参与${relayed_nums}条`); return is_exception || is_outof_maxfollow - || status + || status; } else { log.info('抽奖', '无未转发抽奖'); - return 0 + return 0; } } @@ -295,10 +295,10 @@ class Monitor extends Searcher { /**去重 */ protoLotteryInfo = protoLotteryInfo.filter(({ dyid }) => { if (dyids_map.has(dyid)) { - return false + return false; } dyids_map.set(dyid, false); - return true + return true; }); log.info('筛选动态', `去重后(${protoLotteryInfo.length})`); @@ -311,35 +311,35 @@ class Monitor extends Searcher { .searchDyid(it) .then(hasIt => dyids_map.set(it, hasIt)) ) - ) - log.info('筛选动态', `并发查询本地dyid完毕`); + ); + log.info('筛选动态', '并发查询本地dyid完毕'); } - if (lottery_param[0] !== "APIs" && save_lottery_info_to_file && protoLotteryInfo.length) { - log.info("保存抽奖信息", "保存开始") - await appendLotteryInfoFile(lottery_param[1].toString(), protoLotteryInfo) + if (lottery_param[0] !== 'APIs' && save_lottery_info_to_file && protoLotteryInfo.length) { + log.info('保存抽奖信息', '保存开始'); + await appendLotteryInfoFile(lottery_param[1].toString(), protoLotteryInfo); } - if (lottery_param[0] !== "APIs" && set_lottery_info_url && protoLotteryInfo.length) { - log.info("上传抽奖信息", "上传开始") + if (lottery_param[0] !== 'APIs' && set_lottery_info_url && protoLotteryInfo.length) { + log.info('上传抽奖信息', '上传开始'); await new Promise((resolve) => { send({ url: set_lottery_info_url, - method: "POST", + method: 'POST', headers: { - "content-type": "application/json" + 'content-type': 'application/json' }, contents: protoLotteryInfo, success: ({ body }) => { - log.info("发送获取到的动态数据", body) - resolve() + log.info('发送获取到的动态数据', body); + resolve(); }, failure: err => { - log.error("发送获取到的动态数据", err) - resolve() + log.error('发送获取到的动态数据', err); + resolve(); } - }) - }) + }); + }); } /* 检查动态是否满足要求 */ @@ -357,27 +357,27 @@ class Monitor extends Searcher { log.debug('正在筛选的动态信息', lottery_info); if (lottery_info_type.startsWith('sneak') && sneaktower) { - log.info("筛选动态", `偷塔模式不检查是否已转发(https://t.bilibili.com/${dyid})`) + log.info('筛选动态', `偷塔模式不检查是否已转发(https://t.bilibili.com/${dyid})`); } else { /* 遇到转发过就退出 */ if ( ((!check_if_duplicated || check_if_duplicated >= 2) && is_liked) || ((check_if_duplicated >= 1) && dyids_map.get(dyid)) ) { - log.info("筛选动态", `已转发(https://t.bilibili.com/${dyid})`) - return false + log.info('筛选动态', `已转发(https://t.bilibili.com/${dyid})`); + return false; } } /* 超过指定时间退出 */ if (create_time && now_ts - create_time > max_create_time * 86400) { - log.info("筛选动态", `过时动态(https://t.bilibili.com/${dyid})`) - return false + log.info('筛选动态', `过时动态(https://t.bilibili.com/${dyid})`); + return false; } if (is_charge_lottery) { - log.info("筛选动态", `充电抽奖(https://t.bilibili.com/${dyid})`) - return false + log.info('筛选动态', `充电抽奖(https://t.bilibili.com/${dyid})`); + return false; } const @@ -403,61 +403,61 @@ class Monitor extends Searcher { || (!hasOfficialLottery && chatmodel[1] === '1'), keys = [dyid, m_uid, ori_uid]; - log.debug("筛选动态", { real_uid, mIsFollowed, oriIsFollowed, realIsFollowed, needAt, needTopic, type, isRelayDynamic, key_words, has_key_words, blockword, isBlock, isLottery, isSendChat }) + log.debug('筛选动态', { real_uid, mIsFollowed, oriIsFollowed, realIsFollowed, needAt, needTopic, type, isRelayDynamic, key_words, has_key_words, blockword, isBlock, isLottery, isSendChat }); if ( blacklist.split(',').some(id => keys.some(key => { if (key + '' === id) { - log.info("筛选动态", `黑名单匹配(${id})(https://t.bilibili.com/${dyid})`) - return true + log.info('筛选动态', `黑名单匹配(${id})(https://t.bilibili.com/${dyid})`); + return true; } else { - return false + return false; } })) ) { - return false + return false; } if (block_dynamic_type.includes(type)) { - log.warn("筛选动态", `屏蔽动态类型 ${type}`) - return false + log.warn('筛选动态', `屏蔽动态类型 ${type}`); + return false; } /**屏蔽词 */ if (isBlock) { - log.info("筛选动态", `包含屏蔽词(https://t.bilibili.com/${dyid})`) - return false + log.info('筛选动态', `包含屏蔽词(https://t.bilibili.com/${dyid})`); + return false; } if (reserve_id) { if (disable_reserve_lottery) { - log.info("已关闭预约抽奖功能") + log.info('已关闭预约抽奖功能'); } else { - log.info("预约抽奖", "开始"); - log.info("预约抽奖", `奖品: ${reserve_lottery_text}`); + log.info('预约抽奖', '开始'); + log.info('预约抽奖', `奖品: ${reserve_lottery_text}`); if (hasEnv('NOT_GO_LOTTERY')) { log.info('NOT_GO_LOTTERY', 'ON'); } else { await delay(reserve_lottery_wait); - await bili.reserve_lottery(reserve_id) + await bili.reserve_lottery(reserve_id); } } if (is_not_relay_reserve_lottery === true) { - log.info("预约抽奖", "已关闭预约抽奖转关功能"); - return false + log.info('预约抽奖', '已关闭预约抽奖转关功能'); + return false; } } if (!hasOfficialLottery && model[1] === '1' && !has_key_words && description) { - log.warn("筛选动态", `无关键词动态的描述: ${description}\n\n考虑是否修改设置key_words:\n${key_words.join('\n且满足: ')}`) + log.warn('筛选动态', `无关键词动态的描述: ${description}\n\n考虑是否修改设置key_words:\n${key_words.join('\n且满足: ')}`); } /**若勾选只转已关注 */ if (only_followed && (!mIsFollowed || !oriIsFollowed) ) { - log.info("筛选动态", `只转已关注(https://t.bilibili.com/${dyid})`) - return false + log.info('筛选动态', `只转已关注(https://t.bilibili.com/${dyid})`); + return false; } if (isLottery) { @@ -466,7 +466,7 @@ class Monitor extends Searcher { onelotteryinfo.isOfficialLottery = hasOfficialLottery; /**初始化待关注列表 */ - onelotteryinfo.uid = [] + onelotteryinfo.uid = []; if (!realIsFollowed) { onelotteryinfo.uid.push(real_uid); @@ -476,14 +476,14 @@ class Monitor extends Searcher { let /**转发评语 */ - RandomStr = (getRandomOne(relays) || "!!!") + RandomStr = (getRandomOne(relays) || '!!!') .replace(/\$\{uname\}/g, uname), /**控制字段 */ new_ctrl = []; /* 是否需要带话题 */ if (needTopic) { - RandomStr += needTopic + RandomStr += needTopic; } /* 是否需要@ */ @@ -494,9 +494,9 @@ class Monitor extends Searcher { location: RandomStr.length, length: it[0].length + 1, type: 1 - }) - RandomStr += '@' + it[0] - }) + }); + RandomStr += '@' + it[0]; + }); } /* 是否是转发的动态 */ @@ -509,11 +509,11 @@ class Monitor extends Searcher { location: RandomStr.length + 2, length: uname.length + 1, type: 1 - }) + }); ctrl.map(item => { item.location += addlength; return item; - }).forEach(it => new_ctrl.push(it)) + }).forEach(it => new_ctrl.push(it)); if (!oriIsFollowed) { onelotteryinfo.uid.push(ori_uid); } @@ -528,16 +528,16 @@ class Monitor extends Searcher { /* 是否评论 */ if (isSendChat) { - onelotteryinfo.rid = rid - onelotteryinfo.chat = (getRandomOne(chats) || "!!!") - .replace(/\$\{uname\}/g, uname) + onelotteryinfo.rid = rid; + onelotteryinfo.chat = (getRandomOne(chats) || '!!!') + .replace(/\$\{uname\}/g, uname); } alllotteryinfo.push(onelotteryinfo); } else { - log.info("筛选动态", `非抽奖动态(https://t.bilibili.com/${dyid})`) + log.info('筛选动态', `非抽奖动态(https://t.bilibili.com/${dyid})`); } - }) + }); return alllotteryinfo; } @@ -577,7 +577,7 @@ class Monitor extends Searcher { log.debug('正在转发的动态信息', option); if (hasEnv('NOT_GO_LOTTERY')) { log.info('NOT_GO_LOTTERY', 'ON'); - return 0 + return 0; } let @@ -591,14 +591,14 @@ class Monitor extends Searcher { const copy_chat = getRandomOne( (await bili.getChat(rid, chat_type)) .filter(it => !(new RegExp(copy_blockword.join('|')).test(it[1]))) - ) || [";;;;;;;;;", chat || "!!!"]; + ) || [';;;;;;;;;', chat || '!!!']; chat = copy_chat[1] .replace( new RegExp(copy_chat[0], 'g'), - global_var.get("myUNAME") || '') + global_var.get('myUNAME') || ''); } else { if (is_repost_then_chat) { - chat = chat + relay_chat + chat = chat + relay_chat; } } @@ -610,50 +610,50 @@ class Monitor extends Searcher { chat, chat_type ) - ) + ); if (status === 8 || status === 9) { status = await bili.sendChatWithOcr( rid, - "[doge][doge][doge][doge][doge]", + '[doge][doge][doge][doge][doge]', chat_type - ) + ); } if (status) { - log.warn("抽奖信息", `dyid: ${dyid}, rid: ${rid}, chat_type: ${chat_type}`) - return 1000 + status + log.warn('抽奖信息', `dyid: ${dyid}, rid: ${rid}, chat_type: ${chat_type}`); + return 1000 + status; } } /* 关注 */ if (uid.length) { await try_for_each(uid, async (u) => { - status = await bili.autoAttention(u) + status = await bili.autoAttention(u); if (status === 6) { status = 0; - return false + return false; } if (status) { - log.warn("抽奖信息", `dyid: ${dyid}, uid: ${u}`) - return true + log.warn('抽奖信息', `dyid: ${dyid}, uid: ${u}`); + return true; } else { if (is_not_create_partition !== true) { if (await bili.movePartition(u, this.tagid)) { - log.warn("抽奖信息", `dyid: ${dyid}, uid: ${u} tagid: ${this.tagid}`) + log.warn('抽奖信息', `dyid: ${dyid}, uid: ${u} tagid: ${this.tagid}`); /* 3000系错误 */ - status = 1001 - return true + status = 1001; + return true; } else { - return false + return false; } } else { - return false + return false; } } - }) - if (status) return 2000 + status + }); + if (status) return 2000 + status; } /* 点赞 */ @@ -662,11 +662,11 @@ class Monitor extends Searcher { 5, [3], () => bili.autolike(dyid) - ) + ); if (status) { - log.warn("抽奖信息", `dyid: ${dyid}`) - return 4000 + status + log.warn('抽奖信息', `dyid: ${dyid}`); + return 4000 + status; } } @@ -676,19 +676,19 @@ class Monitor extends Searcher { 5, [3, 4], () => bili.autoRelay( - global_var.get("myUID"), + global_var.get('myUID'), dyid, relay_chat, ctrl) - ) + ); if (status) { - log.warn("抽奖信息", `dyid: ${dyid}`) - return 5000 + status + log.warn('抽奖信息', `dyid: ${dyid}`); + return 5000 + status; } } - return status + return status; } } diff --git a/lib/core/searcher.js b/lib/core/searcher.js index e00ee5e97b..adcad27235 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -1,10 +1,10 @@ const utils = require('../utils'); const bili = require('../net/bili'); -const { send } = require("../net/http"); -const { check_if_duplicated, article_scan_page, article_create_time, not_check_article, get_dynamic_detail_wait, uid_scan_page, search_wait, tag_scan_page } = require("../data/config"); -const d_storage = require("../helper/d_storage") +const { send } = require('../net/http'); +const { check_if_duplicated, article_scan_page, article_create_time, not_check_article, get_dynamic_detail_wait, uid_scan_page, search_wait, tag_scan_page } = require('../data/config'); +const d_storage = require('../helper/d_storage'); -const { log } = utils +const { log } = utils; /** * 解析dynamic_detail_card @@ -60,125 +60,125 @@ const { log } = utils */ function parseDynamicCard(data) { if (data?.card?.desc?.uid) { - return oldParseDynamicCard(data?.card) + return oldParseDynamicCard(data?.card); } let ditem = data?.item; /**临时储存单个动态中的信息 */ let obj = {}; try { const dy_typeenum2num = new Map([ - ["DYNAMIC_TYPE_FORWARD", 1], - ["DYNAMIC_TYPE_DRAW", 2], - ["DYNAMIC_TYPE_WORD", 4], - ["DYNAMIC_TYPE_AV", 8], - ["DYNAMIC_TYPE_ARTICLE", 64] + ['DYNAMIC_TYPE_FORWARD', 1], + ['DYNAMIC_TYPE_DRAW', 2], + ['DYNAMIC_TYPE_WORD', 4], + ['DYNAMIC_TYPE_AV', 8], + ['DYNAMIC_TYPE_ARTICLE', 64] ]); const dy_type2chat_type = new Map([ - ["DYNAMIC_TYPE_FORWARD", 17], - ["DYNAMIC_TYPE_DRAW", 11], - ["DYNAMIC_TYPE_WORD", 17], - ["DYNAMIC_TYPE_AV", 1], - ["DYNAMIC_TYPE_ARTICLE", 12] + ['DYNAMIC_TYPE_FORWARD', 17], + ['DYNAMIC_TYPE_DRAW', 11], + ['DYNAMIC_TYPE_WORD', 17], + ['DYNAMIC_TYPE_AV', 1], + ['DYNAMIC_TYPE_ARTICLE', 12] ]); /* 转发者的UID */ - obj.uid = ditem?.modules?.module_author?.mid || 0 + obj.uid = ditem?.modules?.module_author?.mid || 0; /* 转发者的name */ - obj.uname = ditem?.modules?.module_author?.name || '' + obj.uname = ditem?.modules?.module_author?.name || ''; /* 动态是否点过赞 */ - obj.is_liked = ditem?.modules?.module_stat?.like?.status || false + obj.is_liked = ditem?.modules?.module_stat?.like?.status || false; /* 动态的ts10 */ - obj.create_time = ditem?.modules?.module_author?.pub_ts || 0 + obj.create_time = ditem?.modules?.module_author?.pub_ts || 0; /* 动态类型 */ - obj.type = dy_typeenum2num.get(ditem?.type) || 0 + obj.type = dy_typeenum2num.get(ditem?.type) || 0; /* 用于发送评论 */ - obj.rid_str = ditem?.basic?.comment_id_str || "" + obj.rid_str = ditem?.basic?.comment_id_str || ''; /* 用于发送评论 */ - obj.chat_type = ditem?.basic?.comment_type || 0 + obj.chat_type = ditem?.basic?.comment_type || 0; /* 转发者的动态ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.dynamic_id = ditem?.id_str || "" + obj.dynamic_id = ditem?.id_str || ''; /* 定位@信息 */ obj.ctrl = []; /* 是否有官方抽奖 */ - obj.hasOfficialLottery = false + obj.hasOfficialLottery = false; /* 转发描述 */ - obj.description = "" + obj.description = ''; let _total_len = 0; ditem?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { - if (node.type === "RICH_TEXT_NODE_TYPE_AT") { + if (node.type === 'RICH_TEXT_NODE_TYPE_AT') { obj.ctrl.push({ data: node.rid, location: _total_len, length: node.text.length, type: 1 - }) + }); } /* 是否有官方抽奖 */ - if (node.type === "RICH_TEXT_NODE_TYPE_LOTTERY") { - obj.hasOfficialLottery = true + if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { + obj.hasOfficialLottery = true; } - obj.description += node.orig_text - _total_len += node.text.length - }) + obj.description += node.orig_text; + _total_len += node.text.length; + }); /* 预约抽奖信息 */ - obj.reserve_id = ditem?.modules?.module_dynamic?.additional?.reserve?.rid || 0 - obj.reserve_lottery_text = ditem?.modules?.module_dynamic?.additional?.reserve?.title || "信息丢失" + obj.reserve_id = ditem?.modules?.module_dynamic?.additional?.reserve?.rid || 0; + obj.reserve_lottery_text = ditem?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失'; /* 充电抽奖 */ - if (ditem?.modules?.module_dynamic?.additional?.type === "ADDITIONAL_TYPE_UPOWER_LOTTERY") { - obj.is_charge_lottery = true + if (ditem?.modules?.module_dynamic?.additional?.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { + obj.is_charge_lottery = true; } /* 转发 */ if (obj.type === 1) { /* 被转发者的UID */ - obj.origin_uid = ditem?.orig?.modules?.module_author?.mid || 0 + obj.origin_uid = ditem?.orig?.modules?.module_author?.mid || 0; /* 被转发者的name */ - obj.origin_uname = ditem?.orig?.modules?.module_author?.name || '' + obj.origin_uname = ditem?.orig?.modules?.module_author?.name || ''; /* 源动态的ts10 */ - obj.origin_create_time = ditem?.orig?.modules?.module_author?.pub_ts || 0 + obj.origin_create_time = ditem?.orig?.modules?.module_author?.pub_ts || 0; /* 源动态类型 */ - obj.origin_type = dy_typeenum2num.get(ditem?.orig?.type) || 0 + obj.origin_type = dy_typeenum2num.get(ditem?.orig?.type) || 0; /* 被转发者的rid(用于发评论) */ switch (ditem?.orig?.type) { - case "DYNAMIC_TYPE_DRAW": - obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.draw?.id?.toString() || "" + case 'DYNAMIC_TYPE_DRAW': + obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.draw?.id?.toString() || ''; break; - case "DYNAMIC_TYPE_AV": - obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.archive?.aid || "" + case 'DYNAMIC_TYPE_AV': + obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.archive?.aid || ''; break; - case "DYNAMIC_TYPE_ARTICLE": - obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.article?.id?.toString() || "" + case 'DYNAMIC_TYPE_ARTICLE': + obj.origin_rid_str = ditem?.orig?.modules?.module_dynamic?.major?.article?.id?.toString() || ''; break; default: - obj.origin_rid_str = ditem?.orig?.id_str || "" + obj.origin_rid_str = ditem?.orig?.id_str || ''; break; } /* 用于发送评论 */ - obj.origin_chat_type = dy_type2chat_type.get(ditem?.orig?.type) || 0 + obj.origin_chat_type = dy_type2chat_type.get(ditem?.orig?.type) || 0; /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ - obj.origin_dynamic_id = ditem?.orig?.id_str || "" + obj.origin_dynamic_id = ditem?.orig?.id_str || ''; /* 预约抽奖信息 */ - obj.origin_reserve_id = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.rid || 0 - obj.origin_reserve_lottery_text = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.title || "信息丢失" + obj.origin_reserve_id = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.rid || 0; + obj.origin_reserve_lottery_text = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失'; /* 充电抽奖 */ - if (ditem?.orig?.modules?.module_dynamic?.additional?.type === "ADDITIONAL_TYPE_UPOWER_LOTTERY") { - obj.origin_is_charge_lottery = true + if (ditem?.orig?.modules?.module_dynamic?.additional?.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { + obj.origin_is_charge_lottery = true; } /* 是否有官方抽奖 */ - obj.origin_hasOfficialLottery = false + obj.origin_hasOfficialLottery = false; /* 转发描述 */ - obj.origin_description = "" + obj.origin_description = ''; ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { /* 是否有官方抽奖 */ - if (node.type === "RICH_TEXT_NODE_TYPE_LOTTERY") { - obj.origin_hasOfficialLottery = true + if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { + obj.origin_hasOfficialLottery = true; } - obj.origin_description += node.orig_text - }) + obj.origin_description += node.orig_text; + }); } } catch (e) { - log.error("动态卡片解析", e) + log.error('动态卡片解析', e); } - return obj + return obj; } /** @@ -190,7 +190,7 @@ function oldParseDynamicCard(dynamic_detail_card) { /**临时储存单个动态中的信息 */ let obj = {}; try { - const { desc, card, extension, extend_json = "{}", display = {} } = dynamic_detail_card + const { desc, card, extension, extend_json = '{}', display = {} } = dynamic_detail_card , { is_liked = 1, user_profile = {} } = desc , { info = {} } = user_profile || {} , cardToJson = strToJson(card) @@ -199,15 +199,15 @@ function oldParseDynamicCard(dynamic_detail_card) { , { item } = cardToJson; const dy_type2chat_type = new Map([[1, 17], [2, 11], [4, 17], [8, 1], [64, 12]]); /* 转发者的UID */ - obj.uid = desc.uid + obj.uid = desc.uid; /* 转发者的name */ - obj.uname = info.uname || '' + obj.uname = info.uname || ''; /* 动态是否点过赞 */ - obj.is_liked = is_liked > 0 + obj.is_liked = is_liked > 0; /* 动态的ts10 */ - obj.create_time = desc.timestamp + obj.create_time = desc.timestamp; /* 动态类型 */ - obj.type = desc.type + obj.type = desc.type; /* 用于发送评论 */ obj.rid_str = desc.rid_str.length > 12 ? desc.dynamic_id_str : desc.rid_str; /* 用于发送评论 */ @@ -231,16 +231,16 @@ function oldParseDynamicCard(dynamic_detail_card) { obj.reserve_lottery_text = text; } } - if (extendjsonToJson[""]) { - let r = extendjsonToJson[""].reserve || {}; + if (extendjsonToJson['']) { + let r = extendjsonToJson[''].reserve || {}; let { reserve_id, reserve_lottery } = r; if (reserve_lottery === 1) { - obj.reserve_id = reserve_id + ""; - obj.reserve_lottery_text = "信息丢失"; + obj.reserve_id = reserve_id + ''; + obj.reserve_lottery_text = '信息丢失'; } } if (extend_json.match(/"":\{"lottery/)) { - obj.is_charge_lottery = true + obj.is_charge_lottery = true; } /* 是否有官方抽奖 */ obj.hasOfficialLottery = extension && extension.lott && true; @@ -255,7 +255,7 @@ function oldParseDynamicCard(dynamic_detail_card) { || ''; /* 转发 */ if (obj.type === 1) { - const { origin_extension, origin, origin_extend_json = "{}" } = cardToJson + const { origin_extension, origin, origin_extend_json = '{}' } = cardToJson , originToJson = strToJson(origin) , { add_on_card_info = [] } = display.origin || {} , originExtendjsonToJson = strToJson(origin_extend_json) @@ -265,11 +265,11 @@ function oldParseDynamicCard(dynamic_detail_card) { /* 被转发者的UID */ obj.origin_uid = desc.origin.uid; /* 源动态类型 */ - obj.origin_type = desc.orig_type + obj.origin_type = desc.orig_type; /* 被转发者的rid(用于发评论) */ obj.origin_rid_str = desc.origin.rid_str.length > 12 ? desc.origin.dynamic_id_str : desc.origin.rid_str; /* 用于发送评论 */ - obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0 + obj.origin_chat_type = dy_type2chat_type.get(obj.origin_type) || 0; /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ obj.origin_dynamic_id = desc.orig_dy_id_str; /* 预约抽奖信息 */ @@ -287,16 +287,16 @@ function oldParseDynamicCard(dynamic_detail_card) { obj.origin_reserve_lottery_text = text; } } - if (originExtendjsonToJson[""]) { - let r = originExtendjsonToJson[""].reserve || {}; + if (originExtendjsonToJson['']) { + let r = originExtendjsonToJson[''].reserve || {}; let { reserve_id, reserve_lottery } = r; if (reserve_lottery === 1) { - obj.origin_reserve_id = reserve_id + ""; - obj.origin_reserve_lottery_text = "信息丢失"; + obj.origin_reserve_id = reserve_id + ''; + obj.origin_reserve_lottery_text = '信息丢失'; } } if (origin_extend_json.match(/"":\{"lottery/)) { - obj.origin_is_charge_lottery = true + obj.origin_is_charge_lottery = true; } /* 是否有官方抽奖 */ obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; @@ -309,10 +309,10 @@ function oldParseDynamicCard(dynamic_detail_card) { || ''; } } catch (e) { - log.error("动态卡片解析", e) + log.error('动态卡片解析', e); } - return obj + return obj; } /** @@ -331,11 +331,11 @@ function modifyDynamicRes(res) { } if (cards == null || !cards || !cards.length) { - log.warn('处理动态数据', '未找到任何动态信息') + log.warn('处理动态数据', '未找到任何动态信息'); } - if (typeof has_more === "undefined" - && typeof offset === "undefined") { + if (typeof has_more === 'undefined' + && typeof offset === 'undefined') { log.error('处理动态数据', '该功能已失效'); return null; } @@ -355,14 +355,14 @@ function modifyDynamicRes(res) { */ array = next.has_more === 0 ? [] - : cards.map(oldParseDynamicCard) + : cards.map(oldParseDynamicCard); log.info('处理动态数据', `动态数据读取完毕(${cards.length})(${next.has_more})`); return { modifyDynamicResArray: array, nextinfo: next - } + }; } /** @@ -405,7 +405,7 @@ class Searcher { mDRdata = modifyDynamicRes(OneDynamicInfo); if (mDRdata === null) { - return null + return null; } const @@ -417,7 +417,7 @@ class Searcher { if (nextinfo.has_more === 0) { offset = nextinfo.next_offset; - log.info('检查所有动态', `已经是最后一页了故无法读取更多`); + log.info('检查所有动态', '已经是最后一页了故无法读取更多'); break; } else { /**合并 */ @@ -428,7 +428,7 @@ class Searcher { await utils.delay(time); } - log.info('检查所有动态', `${pages}页信息读取完成`) + log.info('检查所有动态', `${pages}页信息读取完成`); return ({ allModifyDynamicResArray, offset }); } @@ -443,7 +443,7 @@ class Searcher { log.info('获取动态', `开始获取用户${UID}的动态信息`); const AllDynamic = await Searcher.checkAllDynamic(UID, uid_scan_page, search_wait); - if (AllDynamic === null) return null + if (AllDynamic === null) return null; let { allModifyDynamicResArray } = AllDynamic, { length } = allModifyDynamicResArray; @@ -453,10 +453,10 @@ class Searcher { const fomatdata = await allModifyDynamicResArray .filter(d => { if (d.type === 1) { - return true + return true; } else { - length-- - return false + length--; + return false; } }) .reduce(async (pre, cur) => { @@ -466,12 +466,12 @@ class Searcher { is_liked = false; if (!check_if_duplicated || check_if_duplicated >= 2) { - const card = await bili.getOneDynamicByDyid(origin_dynamic_id) - log.info('获取动态', `查看源动态(${origin_dynamic_id})是否点赞 (${length--})`) + const card = await bili.getOneDynamicByDyid(origin_dynamic_id); + log.info('获取动态', `查看源动态(${origin_dynamic_id})是否点赞 (${length--})`); if (card) { - ({ is_liked } = parseDynamicCard(card)) + ({ is_liked } = parseDynamicCard(card)); } - await utils.delay(get_dynamic_detail_wait) + await utils.delay(get_dynamic_detail_wait); } results.push({ @@ -490,10 +490,10 @@ class Searcher { des: cur.origin_description, type: cur.origin_type, hasOfficialLottery: cur.origin_hasOfficialLottery - }) + }); - return results - }, Promise.resolve([])) + return results; + }, Promise.resolve([])); log.info('获取动态', `成功获取用户${UID}的动态信息`); @@ -555,10 +555,10 @@ class Searcher { type: o.type, hasOfficialLottery: o.hasOfficialLottery }; - }) + }); log.info('获取动态', `成功获取带话题#${tag_name}#的动态信息`); - return fomatdata + return fomatdata; } /** @@ -576,11 +576,11 @@ class Searcher { for (const { id, pub_time } of cvs) { let now_time = Math.floor(Date.now() / 1000); if ((now_time - pub_time) / 86400 > article_create_time) { - log.warn("获取动态", `该专栏(${id})创建时间大于设定天数(${article_create_time}天)`) - continue + log.warn('获取动态', `该专栏(${id})创建时间大于设定天数(${article_create_time}天)`); + continue; } const - content = (await bili.getOneArticleByCv(id) || "").split("推荐文章")[0], + content = (await bili.getOneArticleByCv(id) || '').split('推荐文章')[0], dyids = content.match(/[0-9]{18}/g) || [], short_ids = content.match(/(?<=b23.tv\/)[a-zA-Z0-9]{7}/g) || [], short_id_set = [...new Set(short_ids)], @@ -594,18 +594,18 @@ class Searcher { _weight = 0, /**单个专栏中的dyid */ _dyinfos = []; - log.info('获取动态', `提取专栏(${id})中提及的dyid(${length})`) + log.info('获取动态', `提取专栏(${id})中提及的dyid(${length})`); /**遍历某专栏中的dyids */ for (const dyid of dyid_set) { - if (typeof dyid === "string" + if (typeof dyid === 'string' && dyid.length === utils.dyid_length) { - log.info('获取动态', `查看专栏中所提及动态(${dyid}) (${length--})`) - const card = await bili.getOneDynamicByDyid(dyid) + log.info('获取动态', `查看专栏中所提及动态(${dyid}) (${length--})`); + const card = await bili.getOneDynamicByDyid(dyid); if (card) { - await utils.delay(get_dynamic_detail_wait) + await utils.delay(get_dynamic_detail_wait); const parsed_card = parseDynamicCard(card) , { is_liked } = parsed_card; @@ -616,23 +616,23 @@ class Searcher { || ((check_if_duplicated >= 1) && await d_storage.searchDyid(dyid)) ) { - log.info('获取动态', `动态(${dyid})已转发过`) + log.info('获取动态', `动态(${dyid})已转发过`); _weight += 1; } if (_weight >= weight && !not_check_article) { - log.warn('获取动态', `1/2动态曾经转过,该专栏或已查看,故中止`) - _dyinfos = [] - break + log.warn('获取动态', '1/2动态曾经转过,该专栏或已查看,故中止'); + _dyinfos = []; + break; } _dyinfos.push(parsed_card); } } else { - log.warn('获取动态', `动态(${dyid})无效 (${length--})`) + log.warn('获取动态', `动态(${dyid})无效 (${length--})`); } } - dyinfos.push(..._dyinfos) + dyinfos.push(..._dyinfos); } const fomatdata = dyinfos.map(o => { return { @@ -652,10 +652,10 @@ class Searcher { type: o.type, hasOfficialLottery: o.hasOfficialLottery }; - }) + }); log.info('获取动态', `成功获取含关键词${key_words}的专栏信息`); - return fomatdata + return fomatdata; } /** @@ -667,9 +667,9 @@ class Searcher { return new Promise((resolve) => { if (api) { const { strToJson } = utils; - log.info('获取动态', `开始获取链接(${api})中的抽奖信息`) - if (api.startsWith("file://")) { - utils.readLotteryInfoFile(api.substring(7)).then(resolve) + log.info('获取动态', `开始获取链接(${api})中的抽奖信息`); + if (api.startsWith('file://')) { + utils.readLotteryInfoFile(api.substring(7)).then(resolve); } else { send({ url: api, @@ -679,8 +679,8 @@ class Searcher { method: 'GET', success: ({ body }) => { if (body.err_msg) { - log.error("从API响应数据中获取抽奖信息", body.err_msg) - resolve(null) + log.error('从API响应数据中获取抽奖信息', body.err_msg); + resolve(null); } else { const raw_lottery_info = strToJson(body).lottery_info; @@ -693,46 +693,46 @@ class Searcher { , { dyid } = cur; if (!check_if_duplicated || check_if_duplicated >= 2) { - log.info('获取动态', `查看动态(${dyid})是否点赞 (${length--})`) - const card = await bili.getOneDynamicByDyid(dyid) + log.info('获取动态', `查看动态(${dyid})是否点赞 (${length--})`); + const card = await bili.getOneDynamicByDyid(dyid); if (card) { - await utils.delay(get_dynamic_detail_wait) + await utils.delay(get_dynamic_detail_wait); - const { is_liked } = parseDynamicCard(card) + const { is_liked } = parseDynamicCard(card); if (is_liked) { - log.info('获取动态', `动态(${dyid})已转发过`) + log.info('获取动态', `动态(${dyid})已转发过`); } else { - cur.is_liked = is_liked - results.push(cur) + cur.is_liked = is_liked; + results.push(cur); } } } else { - results.push(cur) + results.push(cur); } - return results + return results; - }, Promise.resolve([])) + }, Promise.resolve([])); - resolve(lottery_info) - return + resolve(lottery_info); + return; } } - log.error("从API响应数据中获取抽奖信息", "非Json数据或没有lottery_info或lottery为空") - resolve(null) + log.error('从API响应数据中获取抽奖信息', '非Json数据或没有lottery_info或lottery为空'); + resolve(null); } }, failure: err => { - log.error("从API响应数据中获取抽奖信息", err) - resolve(null) + log.error('从API响应数据中获取抽奖信息', err); + resolve(null); } - }) + }); } } else { - log.warn('获取动态', `链接为空`) - resolve(null) + log.warn('获取动态', '链接为空'); + resolve(null); } }); } @@ -750,14 +750,14 @@ class Searcher { dyinfos = []; for (const dyid of dyids) { - if (typeof dyid === "string" + if (typeof dyid === 'string' && dyid.length === utils.dyid_length) { - log.info('获取动态', `查看Txt中所提及动态(${dyid}) (${length--})`) - const card = await bili.getOneDynamicByDyid(dyid) + log.info('获取动态', `查看Txt中所提及动态(${dyid}) (${length--})`); + const card = await bili.getOneDynamicByDyid(dyid); if (card) { - await utils.delay(get_dynamic_detail_wait) + await utils.delay(get_dynamic_detail_wait); const parsed_card = parseDynamicCard(card) , { is_liked } = parsed_card; @@ -768,14 +768,14 @@ class Searcher { || ((check_if_duplicated >= 1) && await d_storage.searchDyid(dyid)) ) { - log.info('获取动态', `动态(${dyid})已转发过`) - continue + log.info('获取动态', `动态(${dyid})已转发过`); + continue; } dyinfos.push(parsed_card); } } else { - log.warn('获取动态', `动态(${dyid})无效 (${length--})`) + log.warn('获取动态', `动态(${dyid})无效 (${length--})`); } } const fomatdata = dyinfos.map(o => { @@ -796,10 +796,10 @@ class Searcher { type: o.type, hasOfficialLottery: o.hasOfficialLottery }; - }) - log.info('获取动态', `成功获取txt信息`); + }); + log.info('获取动态', '成功获取txt信息'); - return fomatdata + return fomatdata; } } diff --git a/lib/data/config.js b/lib/data/config.js index d4390c1c7f..dc7e824406 100644 --- a/lib/data/config.js +++ b/lib/data/config.js @@ -75,15 +75,15 @@ const config = { * API发送数据类型 {LotteryInfo[]} * 上传抽奖信息的链接字符串 */ - set_lottery_info_url: "", + set_lottery_info_url: '', /** * 动态中的关键词(表示须同时满足以下条件) * 符合js正则表达式的字符串 */ key_words: [ - "[抽奖送揪]|福利", - "[转关评粉]|参与" + '[抽奖送揪]|福利', + '[转关评粉]|参与' ], /** @@ -308,7 +308,7 @@ const config = { /** * 屏蔽词 */ - blockword: ["脚本", "抽奖号", "钓鱼"], + blockword: ['脚本', '抽奖号', '钓鱼'], /** * 转发并评论 @@ -370,10 +370,10 @@ const config = { * - 优先级递增 */ notice_key_words: [ - "~预约成功|预约主题", - "中奖|获得|填写|写上|提供|收货地址|支付宝账号|码|大会员", - "~你的账号在新设备或平台登录成功", - "~你预约的直播已开始" + '~预约成功|预约主题', + '中奖|获得|填写|写上|提供|收货地址|支付宝账号|码|大会员', + '~你的账号在新设备或平台登录成功', + '~你预约的直播已开始' ], /** @@ -457,23 +457,23 @@ const config = { */ raw_config() { delete require.cache[config_file]; - return require(config_file) + return require(config_file); }, /** * @param {string} n */ updata(n) { - this.init() - this.setObject(this.raw_config()[`config_${n}`]) + this.init(); + this.setObject(this.raw_config()[`config_${n}`]); }, init() { - this.setObject(this.raw_config()["default_config"]) + this.setObject(this.raw_config()['default_config']); }, setObject(o = {}) { - Object.entries(o).forEach(([k, v]) => this[k] = v) + Object.entries(o).forEach(([k, v]) => this[k] = v); } }; diff --git a/lib/data/env.js b/lib/data/env.js index e3e677150e..992898a8d7 100644 --- a/lib/data/env.js +++ b/lib/data/env.js @@ -1,4 +1,4 @@ -const { env_file } = require("../utils"); +const { env_file } = require('../utils'); const env = { /** @@ -7,28 +7,28 @@ const env = { */ raw_env() { delete require.cache[env_file]; - return require(env_file) + return require(env_file); }, init() { - const raw_env = this.raw_env() + const raw_env = this.raw_env(); this.setEnv({ - ...raw_env["account_parm"], - ...raw_env["push_parm"] - }) + ...raw_env['account_parm'], + ...raw_env['push_parm'] + }); }, /** * @returns {Object[]} */ get_multiple_account() { - return this.raw_env()["multiple_account_parm"] + return this.raw_env()['multiple_account_parm']; }, setEnv(o) { process.env = { ...process.env, ...o - } + }; } -} +}; module.exports = env; \ No newline at end of file diff --git a/lib/data/global_var.js b/lib/data/global_var.js index ee45c3b757..b1b0cb5094 100644 --- a/lib/data/global_var.js +++ b/lib/data/global_var.js @@ -1,13 +1,13 @@ -const { getRandomOne, createDir, createFile, dyids_dir } = require("../utils"); -const config = require("../data/config"); +const { getRandomOne, createDir, createFile, dyids_dir } = require('../utils'); +const config = require('../data/config'); let global_var = { inner: {}, get(key) { - return this.inner[key] + return this.inner[key]; }, set(key, value) { - this.inner[key] = value + this.inner[key] = value; }, /** * 全局变量初始化 @@ -22,28 +22,28 @@ let global_var = { ['DedeUserID', 'myUID'], ['bili_jct', 'csrf']]), LotteryOrderMap = new Map([ - [0, "UIDs"], - [1, "TAGs"], - [2, "Articles"], - [3, "APIs"], - [4, "TxT"], + [0, 'UIDs'], + [1, 'TAGs'], + [2, 'Articles'], + [3, 'APIs'], + [4, 'TxT'], ]); config.updata(num); if (!/buvid3/.test(cookie)) { - const charset = "0123456789ABCDEF".split(""); - const buvid3 = "x".repeat(8).split("").map(() => getRandomOne(charset)).join("") - + "-" - + "x".repeat(4).split("").map(() => getRandomOne(charset)).join("") - + "-" - + "x".repeat(4).split("").map(() => getRandomOne(charset)).join("") - + "-" - + "x".repeat(4).split("").map(() => getRandomOne(charset)).join("") - + "-" - + "x".repeat(17).split("").map(() => getRandomOne(charset)).join("") - + "infoc"; - this.set('cookie', cookie + ";" + buvid3); + const charset = '0123456789ABCDEF'.split(''); + const buvid3 = 'x'.repeat(8).split('').map(() => getRandomOne(charset)).join('') + + '-' + + 'x'.repeat(4).split('').map(() => getRandomOne(charset)).join('') + + '-' + + 'x'.repeat(4).split('').map(() => getRandomOne(charset)).join('') + + '-' + + 'x'.repeat(4).split('').map(() => getRandomOne(charset)).join('') + + '-' + + 'x'.repeat(17).split('').map(() => getRandomOne(charset)).join('') + + 'infoc'; + this.set('cookie', cookie + ';' + buvid3); } else { this.set('cookie', cookie); } @@ -58,13 +58,13 @@ let global_var = { this.set('Lottery', LotteryOrder .map(it => LotteryOrderMap.get(it)) - .filter(it => typeof it === "string") + .filter(it => typeof it === 'string') .map(lottery_option => config[lottery_option].map(it => [lottery_option, it])) .flat() ); } await createDir('dyids'); - await createFile(dyids_dir, num < 2 ? 'dyid.txt' : `dyid${num}.txt`, '', 'a') + await createFile(dyids_dir, num < 2 ? 'dyid.txt' : `dyid${num}.txt`, '', 'a'); } }; diff --git a/lib/helper/d_storage.js b/lib/helper/d_storage.js index c57710a44f..46c54faf17 100644 --- a/lib/helper/d_storage.js +++ b/lib/helper/d_storage.js @@ -1,4 +1,4 @@ -const { log, readDyidFile, writeDyidFile, dyid_length } = require("../utils"); +const { log, readDyidFile, writeDyidFile, dyid_length } = require('../utils'); const d_storage = { /** @@ -13,17 +13,17 @@ const d_storage = { let status = false; rs.on('data', chunk => { if (Rdyid.test(chunk)) { - status = true + status = true; } - }) + }); rs.on('end', () => { - resolve(status) - }) + resolve(status); + }); rs.on('error', err => { - log.error('搜索dyid', err) - resolve(status) - }) - }) + log.error('搜索dyid', err); + resolve(status); + }); + }); }, /** * 更新dyid @@ -32,21 +32,21 @@ const d_storage = { updateDyid: (dyid) => { log.info('更新dyid', `写入${dyid}`); if (dyid.length !== dyid_length) { - log.error('更新dyid', `dyid(${dyid})长度不为18 若出现此问题请即时通知开发者`) + log.error('更新dyid', `dyid(${dyid})长度不为18 若出现此问题请即时通知开发者`); } return new Promise((resolve) => { const ws = writeDyidFile(Number(process.env.NUMBER)); ws.write(dyid + ',', () => { ws.destroy(); - resolve() - }) + resolve(); + }); ws.on('error', err => { - log.error('更新dyid', err) - resolve() - }) + log.error('更新dyid', err); + resolve(); + }); }); } -} +}; module.exports = d_storage; \ No newline at end of file diff --git a/lib/helper/event_bus.js b/lib/helper/event_bus.js index 69cf334d0e..af4e8164cc 100644 --- a/lib/helper/event_bus.js +++ b/lib/helper/event_bus.js @@ -15,11 +15,11 @@ const event_bus = { }, flush() { this.event_list.forEach(event => { - this.ee.removeAllListeners(event) + this.ee.removeAllListeners(event); }); this.event_list = []; } -} +}; module.exports = event_bus; diff --git a/lib/helper/notify.js b/lib/helper/notify.js index 23bd753ddf..3ebe504f40 100644 --- a/lib/helper/notify.js +++ b/lib/helper/notify.js @@ -1,6 +1,6 @@ -const { log } = require("../utils"); -const { send } = require("../net/http"); -const { createTransport } = require("nodemailer"); +const { log } = require('../utils'); +const { send } = require('../net/http'); +const { createTransport } = require('nodemailer'); // =======================================微信server酱通知设置区域=========================================== //此处填你申请的SCKEY. @@ -107,24 +107,24 @@ if (process.env.QQ_MODE) { if (process.env.BARK_PUSH) { if (process.env.BARK_PUSH.indexOf('https') > -1 || process.env.BARK_PUSH.indexOf('http') > -1) { //兼容BARK自建用户 - BARK_PUSH = process.env.BARK_PUSH + BARK_PUSH = process.env.BARK_PUSH; } else { - BARK_PUSH = `https://api.day.app/${process.env.BARK_PUSH}` + BARK_PUSH = `https://api.day.app/${process.env.BARK_PUSH}`; } if (process.env.BARK_SOUND) { - BARK_SOUND = process.env.BARK_SOUND + BARK_SOUND = process.env.BARK_SOUND; } } else { if (BARK_PUSH && BARK_PUSH.indexOf('https') === -1 && BARK_PUSH.indexOf('http') === -1) { //兼容BARK本地用户只填写设备码的情况 - BARK_PUSH = `https://api.day.app/${BARK_PUSH}` + BARK_PUSH = `https://api.day.app/${BARK_PUSH}`; } } if (process.env.PUSHDEER_URL) { - PUSHDEER_URL = process.env.PUSHDEER_URL + PUSHDEER_URL = process.env.PUSHDEER_URL; } else { - PUSHDEER_URL = "https://api2.pushdeer.com/message/push"; + PUSHDEER_URL = 'https://api2.pushdeer.com/message/push'; } if (process.env.PUSHDEER_PUSHKEY) { @@ -163,7 +163,7 @@ if (process.env.QYWX_KEY) { } if (process.env.IGOT_PUSH_KEY) { - IGOT_PUSH_KEY = process.env.IGOT_PUSH_KEY + IGOT_PUSH_KEY = process.env.IGOT_PUSH_KEY; } if (process.env.PUSH_PLUS_TOKEN) { @@ -200,7 +200,7 @@ if (process.env.SMTP_TO_USER) { if (process.env.GOTIFY_URL) { GOTIFY_URL = process.env.GOTIFY_URL; if (process.env.GOTIFY_APPKEY) { - GOTIFY_APPKEY = process.env.GOTIFY_APPKEY + GOTIFY_APPKEY = process.env.GOTIFY_APPKEY; } } @@ -208,7 +208,7 @@ if (process.env.GOTIFY_URL) { async function sendNotify(text, desp, params = {}) { if (process.env.NOTE) { - desp = `帐号备注: ${process.env.NOTE}\n${desp}` + desp = `帐号备注: ${process.env.NOTE}\n${desp}`; } //提供多种通知方式 await Promise.all([ @@ -240,7 +240,7 @@ async function sendNotify(text, desp, params = {}) { email(text, desp), // Gotify gotifyNotify(text, desp) - ]) + ]); } function serverNotify(text, desp) { @@ -263,29 +263,29 @@ function serverNotify(text, desp) { try { const data = JSON.parse(res.body); if (data.errno === 0) { - log.info('发送通知', 'server酱发送通知消息成功') + log.info('发送通知', 'server酱发送通知消息成功'); } else if (data.errno === 1024) { // 一分钟内发送相同的内容会触发 - log.error('发送通知', `server酱发送通知消息异常: ${data.errmsg}`) + log.error('发送通知', `server酱发送通知消息异常: ${data.errmsg}`); } else { - log.error('发送通知', `server酱发送通知消息异常\n${JSON.stringify(data)}`) + log.error('发送通知', `server酱发送通知消息异常\n${JSON.stringify(data)}`); } } catch (error) { log.error('发送通知', error); } finally { - resolve() + resolve(); } }, failure: err => { - log.error('发送通知', 'server酱 发送通知调用API失败!!' + err) - resolve() + log.error('发送通知', 'server酱 发送通知调用API失败!!' + err); + resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供server酱的SCKEY,取消微信推送消息通知'); - resolve() + resolve(); } - }) + }); } function serverNotifyTurbo(text, desp) { @@ -308,26 +308,26 @@ function serverNotifyTurbo(text, desp) { try { const data = JSON.parse(res.body); if (data.code === 0) { - log.info('发送通知', 'server酱(Turbo版)发送通知消息成功') + log.info('发送通知', 'server酱(Turbo版)发送通知消息成功'); } else { - log.error('发送通知', `server酱(Turbo版)发送通知消息异常\n${JSON.stringify(data)}`) + log.error('发送通知', `server酱(Turbo版)发送通知消息异常\n${JSON.stringify(data)}`); } } catch (error) { log.error('发送通知', error); } finally { - resolve() + resolve(); } }, failure: err => { - log.error('发送通知', 'server酱(Turbo版) 发送通知调用API失败!!' + err) - resolve() + log.error('发送通知', 'server酱(Turbo版) 发送通知调用API失败!!' + err); + resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供server酱(Turbo版)的SCKEY,取消微信推送消息通知'); - resolve() + resolve(); } - }) + }); } function coolPush(text, desp) { @@ -335,18 +335,18 @@ function coolPush(text, desp) { if (QQ_SKEY) { let pushMode = function (t) { switch (t) { - case "send": - return "个人"; - case "group": - return "QQ群"; - case "wx": - return "微信"; - case "ww": - return "企业微信"; + case 'send': + return '个人'; + case 'group': + return 'QQ群'; + case 'wx': + return '微信'; + case 'ww': + return '企业微信'; default: - return "未知方式" + return '未知方式'; } - } + }; send({ method: 'POST', url: `https://push.xuthus.cc/${QQ_MODE}/${QQ_SKEY}`, @@ -356,34 +356,34 @@ function coolPush(text, desp) { }, headers: { accept: 'application/json, text/plain, */*', - "content-type": "text/plain" + 'content-type': 'text/plain' }, success: res => { try { const data = JSON.parse(res.body); if (data.code === 200) { - log.info('发送通知', `酷推发送${pushMode(QQ_MODE)}通知消息成功`) + log.info('发送通知', `酷推发送${pushMode(QQ_MODE)}通知消息成功`); } else if (data.code === 400) { - log.error('发送通知', `QQ酷推(Cool Push)发送${pushMode(QQ_MODE)}推送失败:${data}`) + log.error('发送通知', `QQ酷推(Cool Push)发送${pushMode(QQ_MODE)}推送失败:${data}`); } else { log.error('发送通知', `酷推推送异常: ${data.msg}`); } } catch (error) { log.error('发送通知', error); } finally { - resolve() + resolve(); } }, failure: err => { - log.error('发送通知', `酷推 发送${pushMode(QQ_MODE)}通知调用API失败!!${err}`) - resolve() + log.error('发送通知', `酷推 发送${pushMode(QQ_MODE)}通知调用API失败!!${err}`); + resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供酷推的SKEY,取消QQ推送消息通知'); - resolve() + resolve(); } - }) + }); } function barkNotify(text, desp, params = {}) { @@ -406,26 +406,26 @@ function barkNotify(text, desp, params = {}) { try { const data = JSON.parse(res.body); if (data.code === 200) { - log.info('发送通知', 'Bark APP发送通知消息成功') + log.info('发送通知', 'Bark APP发送通知消息成功'); } else { log.error('发送通知', `${data.message}`); } } catch (error) { log.error('发送通知', error); } finally { - resolve() + resolve(); } }, failure: err => { log.error('发送通知', 'Bark APP发送通知调用API失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供Bark的APP推送BARK_PUSH,取消Bark推送消息通知'); - resolve() + resolve(); } - }) + }); } function pushdeerNotify(text, desp) { @@ -438,7 +438,7 @@ function pushdeerNotify(text, desp) { pushkey: PUSHDEER_PUSHKEY, text, desp, - type: "markdown" + type: 'markdown' }, config: { retry: false @@ -447,26 +447,26 @@ function pushdeerNotify(text, desp) { try { const data = JSON.parse(res.body); if (data.code === 0) { - log.info('发送通知', 'Pushdeer推送发送通知消息成功') + log.info('发送通知', 'Pushdeer推送发送通知消息成功'); } else { - log.error('发送通知', `Pushdeer推送发送通知消息异常\n${JSON.stringify(data)}`) + log.error('发送通知', `Pushdeer推送发送通知消息异常\n${JSON.stringify(data)}`); } } catch (error) { log.error('发送通知', error); } finally { - resolve() + resolve(); } }, failure: err => { - log.error('发送通知', 'Pushdeer推送发送通知调用API失败!!' + err) - resolve() + log.error('发送通知', 'Pushdeer推送发送通知调用API失败!!' + err); + resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供Pushdeer推送所需的PUSHDEER_URL 和 PUSHDEER_PUSHKEY, 取消Pushdeer推送消息通知'); - resolve() + resolve(); } - }) + }); } function tgBotNotify(text, desp) { @@ -492,35 +492,35 @@ function tgBotNotify(text, desp) { try { const data = JSON.parse(res.body); if (data.ok) { - log.info('发送通知', 'Telegram发送通知消息完成。') + log.info('发送通知', 'Telegram发送通知消息完成。'); } else if (data.error_code === 400) { - log.error('发送通知', '请主动给bot发送一条消息并检查接收用户ID是否正确。') + log.error('发送通知', '请主动给bot发送一条消息并检查接收用户ID是否正确。'); } else if (data.error_code === 401) { - log.error('发送通知', 'Telegram bot token 填写错误。') + log.error('发送通知', 'Telegram bot token 填写错误。'); } } catch (error) { log.error('发送通知', error); } finally { - resolve() + resolve(); } }, failure: err => { - log.error('发送通知', 'telegram发送通知消息失败!!' + err) - resolve() + log.error('发送通知', 'telegram发送通知消息失败!!' + err); + resolve(); } - } + }; if (TG_PROXY_HOST && TG_PROXY_PORT) { options.proxy = { - url: "http://" + TG_PROXY_HOST + ":" + TG_PROXY_PORT, + url: 'http://' + TG_PROXY_HOST + ':' + TG_PROXY_PORT, auth_headers: [] - } + }; } - send(options) + send(options); } else { log.debug('发送通知', '您未提供telegram机器人推送所需的TG_BOT_TOKEN和TG_USER_ID,取消telegram推送消息通知'); - resolve() + resolve(); } - }) + }); } function ddBotNotify(text, desp) { @@ -533,7 +533,7 @@ function ddBotNotify(text, desp) { const result = encodeURIComponent(hmac.digest().toString('base64')); send({ method: 'POST', - url: `https://oapi.dingtalk.com/robot/send`, + url: 'https://oapi.dingtalk.com/robot/send', query: { access_token: DD_BOT_TOKEN, timestamp: dateNow, @@ -543,7 +543,7 @@ function ddBotNotify(text, desp) { retry: false }, contents: { - msgtype: "text", + msgtype: 'text', text: { content: `${text}\n\n${desp}` } @@ -556,9 +556,9 @@ function ddBotNotify(text, desp) { try { const data = JSON.parse(res.body); if (data.errcode === 0) { - log.info('发送通知', '钉钉发送通知消息完成。') + log.info('发送通知', '钉钉发送通知消息完成。'); } else { - log.error('发送通知', `${data.errmsg}`) + log.error('发送通知', `${data.errmsg}`); } } catch (e) { log.error('发送通知', e); @@ -567,14 +567,14 @@ function ddBotNotify(text, desp) { } }, failure: err => { - log.error('发送通知', '钉钉发送通知消息失败!!' + err) - resolve() + log.error('发送通知', '钉钉发送通知消息失败!!' + err); + resolve(); } - }) + }); } else if (DD_BOT_TOKEN) { send({ method: 'POST', - url: `https://oapi.dingtalk.com/robot/send`, + url: 'https://oapi.dingtalk.com/robot/send', query: { access_token: DD_BOT_TOKEN }, @@ -582,7 +582,7 @@ function ddBotNotify(text, desp) { retry: false }, contents: { - msgtype: "text", + msgtype: 'text', text: { content: `${text}\n\n${desp}` } @@ -595,9 +595,9 @@ function ddBotNotify(text, desp) { try { const data = JSON.parse(res.body); if (data.errcode === 0) { - log.info('发送通知', '钉钉发送通知消息完成。') + log.info('发送通知', '钉钉发送通知消息完成。'); } else { - log.error('发送通知', `${data.errmsg}`) + log.error('发送通知', `${data.errmsg}`); } } catch (e) { log.error('发送通知', e); @@ -609,12 +609,12 @@ function ddBotNotify(text, desp) { log.error('发送通知', '钉钉发送通知消息失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供钉钉机器人推送所需的DD_BOT_TOKEN或者DD_BOT_SECRET,取消钉钉推送消息通知'); - resolve() + resolve(); } - }) + }); } function qywxAmNotify(text, desp) { @@ -623,7 +623,7 @@ function qywxAmNotify(text, desp) { const QYWX_AM_AY = QYWX_AM.split(','); send({ method: 'POST', - url: `https://qyapi.weixin.qq.com/cgi-bin/gettoken`, + url: 'https://qyapi.weixin.qq.com/cgi-bin/gettoken', contents: { corpid: `${QYWX_AM_AY[0]}`, corpsecret: `${QYWX_AM_AY[1]}`, @@ -676,7 +676,7 @@ function qywxAmNotify(text, desp) { log.error('发送通知', '企业微信应用发送通知消息失败!!' + err); resolve(); } - }) + }); } catch (e) { log.error('发送通知', e); } finally { @@ -687,7 +687,7 @@ function qywxAmNotify(text, desp) { log.error('发送通知', '企业微信应用发送通知消息失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供企业微信应用所需的QYWX_AM,取消企业微信应用推送消息通知'); resolve(); @@ -732,7 +732,7 @@ function qywxBotNotify(text, desp) { log.error('发送通知', '企业微信发送通知消息失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供企业微信机器人推送所需的QYWX_KEY,取消企业微信推送消息通知'); resolve(); @@ -744,11 +744,11 @@ function iGotNotify(text, desp, params = {}) { return new Promise(resolve => { if (IGOT_PUSH_KEY) { // 校验传入的IGOT_PUSH_KEY是否有效 - const IGOT_PUSH_KEY_REGX = new RegExp("^[a-zA-Z0-9]{24}$") + const IGOT_PUSH_KEY_REGX = new RegExp('^[a-zA-Z0-9]{24}$'); if (!IGOT_PUSH_KEY_REGX.test(IGOT_PUSH_KEY)) { - log.error('发送通知', '您所提供的IGOT_PUSH_KEY无效') - resolve() - return + log.error('发送通知', '您所提供的IGOT_PUSH_KEY无效'); + resolve(); + return; } send({ method: 'POST', @@ -769,9 +769,9 @@ function iGotNotify(text, desp, params = {}) { try { const data = JSON.parse(res.body); if (data.ret === 0) { - log.info('发送通知', 'iGot发送通知消息成功') + log.info('发送通知', 'iGot发送通知消息成功'); } else { - log.error('发送通知', `iGot发送通知消息失败:${data.errMsg}`) + log.error('发送通知', `iGot发送通知消息失败:${data.errMsg}`); } } catch (e) { log.error('发送通知', e); @@ -780,15 +780,15 @@ function iGotNotify(text, desp, params = {}) { } }, failure: err => { - log.error('发送通知', 'iGot 发送通知调用API失败!!' + err) + log.error('发送通知', 'iGot 发送通知调用API失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供iGot的推送IGOT_PUSH_KEY,取消iGot推送消息通知'); - resolve() + resolve(); } - }) + }); } function pushPlusNotify(text, desp) { @@ -814,9 +814,9 @@ function pushPlusNotify(text, desp) { try { const data = JSON.parse(res.body); if (data.code === 200) { - log.info('发送通知', `push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息完成。`) + log.info('发送通知', `push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息完成。`); } else { - log.error('发送通知', `push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息失败:${data.msg}`) + log.error('发送通知', `push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息失败:${data.msg}`); } } catch (e) { log.error('发送通知', e); @@ -825,15 +825,15 @@ function pushPlusNotify(text, desp) { } }, failure: err => { - log.error('发送通知', `push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息失败!!${err}`) + log.error('发送通知', `push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息失败!!${err}`); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供push+推送所需的PUSH_PLUS_TOKEN,取消push+推送消息通知'); - resolve() + resolve(); } - }) + }); } function gotifyNotify(text, desp) { @@ -856,19 +856,19 @@ function gotifyNotify(text, desp) { }, success: () => { // HTTP 响应码 200 就说明成功了 - log.info('发送通知', 'Gotify 发送通知消息成功') + log.info('发送通知', 'Gotify 发送通知消息成功'); resolve(); }, failure: err => { - log.error('发送通知', 'Gotify 发送通知调用API失败!!' + err) + log.error('发送通知', 'Gotify 发送通知调用API失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供Gotify推送所需的GOTIFY_APPKEY,取消Gotify推送消息通知'); - resolve() + resolve(); } - }) + }); } async function qmsg(text, desp) { @@ -878,7 +878,7 @@ async function qmsg(text, desp) { method: 'POST', url: 'https://qmsg.zendee.cn/send/' + QMSG_KEY, contents: { - msg: text + "\n\n" + desp, + msg: text + '\n\n' + desp, qq: QMSG_QQ }, config: { @@ -892,9 +892,9 @@ async function qmsg(text, desp) { try { const data = JSON.parse(res.body); if (data.code === 200) { - log.info('发送通知', `qmsg发送通知消息完成。`) + log.info('发送通知', 'qmsg发送通知消息完成。'); } else { - log.error('发送通知', `qmsg通知消息失败: ${data.reason}`) + log.error('发送通知', `qmsg通知消息失败: ${data.reason}`); } } catch (e) { log.error('发送通知', e); @@ -903,15 +903,15 @@ async function qmsg(text, desp) { } }, failure: err => { - log.error('发送通知', `qmsg通知消息失败!!` + err) + log.error('发送通知', 'qmsg通知消息失败!!' + err); resolve(); } - }) + }); } else { log.debug('发送通知', '您未提供qmsg推送所需的QMSG_KEY,取消qmsg推送消息通知'); - resolve() + resolve(); } - }) + }); } async function email(text, desp) { @@ -929,10 +929,10 @@ async function email(text, desp) { to: SMTP_TO_USER, subject: text, text: desp, - }) + }); } catch (e) { log.error('发送通知', `email发送失败 原因: ${e.message}`); - return + return; } log.info('发送通知', 'email发送成功'); } else { @@ -940,4 +940,4 @@ async function email(text, desp) { } } -module.exports = { sendNotify } +module.exports = { sendNotify }; diff --git a/lib/helper/randomDynamic.js b/lib/helper/randomDynamic.js index 2a93bea324..23811aabbd 100644 --- a/lib/helper/randomDynamic.js +++ b/lib/helper/randomDynamic.js @@ -1,6 +1,6 @@ -const config = require("../data/config"); -const bili = require("../net/bili"); -const utils = require("../utils"); +const config = require('../data/config'); +const bili = require('../net/bili'); +const utils = require('../utils'); /** * 随机动态 @@ -8,22 +8,22 @@ const utils = require("../utils"); * @returns */ async function randomDynamic(num) { - let dynamics = [] + let dynamics = []; const { create_dy_type, dy_contents, random_dynamic_wait } = config, hasShareVideo = create_dy_type === -1 || create_dy_type === 1, hasRandomCreate = create_dy_type === -1 || create_dy_type === 0 || typeof create_dy_type === 'undefined'; if (hasShareVideo) { - dynamics = await bili.getTopRcmd() + dynamics = await bili.getTopRcmd(); for (let index = 0; dynamics.length < num; index++) { - dynamics.push(...await bili.getTopRcmd()) + dynamics.push(...await bili.getTopRcmd()); } } if (hasRandomCreate) { for (let index = 0; index < num; index++) { - dynamics.push(utils.getRandomOne(dy_contents)) + dynamics.push(utils.getRandomOne(dy_contents)); } } @@ -31,13 +31,13 @@ async function randomDynamic(num) { utils.shuffle(dynamics).slice(0, num), async (dynamic) => { await utils.delay(random_dynamic_wait); - if (dynamic instanceof Array && dynamic.length === 2 && typeof dynamic[0] === "number") { - await bili.shareVideo(...dynamic) + if (dynamic instanceof Array && dynamic.length === 2 && typeof dynamic[0] === 'number') { + await bili.shareVideo(...dynamic); } else { - await bili.createDynamic(dynamic) + await bili.createDynamic(dynamic); } } - ) + ); } -module.exports = { randomDynamic } \ No newline at end of file +module.exports = { randomDynamic }; \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index f345c4fd9b..e672b36ffc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,10 +2,10 @@ const { login } = require('./login'); const { isMe } = require('./check'); const { clear } = require('./clear'); const { start } = require('./lottery'); -const { account } = require("./account"); -const global_var = require('./data/global_var') -const bili = require('./net/bili') -const { log } = require('./utils') +const { account } = require('./account'); +const global_var = require('./data/global_var'); +const bili = require('./net/bili'); +const { log } = require('./utils'); const { sendNotify } = require('./helper/notify'); /** @@ -13,16 +13,16 @@ const { sendNotify } = require('./helper/notify'); * @param {string} num */ async function checkCookie(num) { - const My_UID = global_var.get("myUID"); + const My_UID = global_var.get('myUID'); if (await bili.getMyinfo()) { log.info('Cookie有效性检测', `成功登录 UID:${My_UID}`); return true; } else { log.error('Cookie有效性检测', `登录失败 COOKIE${num} 已失效 UID:${My_UID}`); - await sendNotify('动态抽奖出错-登录失败', `COOKIE${num} 已失效 UID:${My_UID}`) + await sendNotify('动态抽奖出错-登录失败', `COOKIE${num} 已失效 UID:${My_UID}`); return false; } } -module.exports = { login, start, isMe, clear, checkCookie, account } \ No newline at end of file +module.exports = { login, start, isMe, clear, checkCookie, account }; \ No newline at end of file diff --git a/lib/login.js b/lib/login.js index b55b33102b..784ebd7f18 100644 --- a/lib/login.js +++ b/lib/login.js @@ -1,5 +1,5 @@ const { readFileSync, writeFileSync } = require('fs'); -const { log, env_file } = require("./utils"); +const { log, env_file } = require('./utils'); /** * 扫码登陆 @@ -10,17 +10,17 @@ async function login(num) { const { pcLogin } = require('@catlair/blogin'); const loginInfo = await pcLogin(); if (!loginInfo) { - log.error("扫码登陆", "失败/取消"); + log.error('扫码登陆', '失败/取消'); return; } - log.info("扫码登陆", "登录成功"); + log.info('扫码登陆', '登录成功'); JSON.stringify(loginInfo, null, 2); const uid = `${loginInfo.mid}`; const cookie = `${loginInfo.cookie}`; - log.info("账号UID", uid); - log.info("Cookie", cookie); + log.info('账号UID', uid); + log.info('Cookie', cookie); if (replaceCookie(env_file, uid, cookie)) { - log.info("扫码登陆", `账号${num}已进行cookie自动更新,如未能生效请手动复制在env.js内替换。路径:${env_file}`); + log.info('扫码登陆', `账号${num}已进行cookie自动更新,如未能生效请手动复制在env.js内替换。路径:${env_file}`); } } catch (error) { log.error(error); @@ -41,7 +41,7 @@ function replaceCookie(filePath, uid, oldCK) { const newCK = content.replaceAll(reg, substring => { let quote = substring.at(0) || ''; /['"]/.test(quote) || (quote = ''); - const quote2 = oldCK.includes("'") + const quote2 = oldCK.includes('\'') ? '"' : substring.match(/^['"]?COOKIE['"]?:\s?(['"])/)?.[1] || '"'; return `${quote}COOKIE${quote}: ${quote2}${oldCK}${quote2}`; @@ -50,9 +50,9 @@ function replaceCookie(filePath, uid, oldCK) { writeFileSync(filePath, newCK); return true; } catch (error) { - log.error("扫码登陆", error); + log.error('扫码登陆', error); } return false; } -module.exports = { login } \ No newline at end of file +module.exports = { login }; \ No newline at end of file diff --git a/lib/lottery.js b/lib/lottery.js index b6f5d9cf5f..0d11c1ab16 100644 --- a/lib/lottery.js +++ b/lib/lottery.js @@ -15,11 +15,11 @@ async function createRandomDynamic(num) { { allModifyDynamicResArray } = (await utils.retryfn( 3, [null], - () => Searcher.checkAllDynamic(global_var.get("myUID"), 1) + () => Searcher.checkAllDynamic(global_var.get('myUID'), 1) )) || { allModifyDynamicResArray: [] }, { type, origin_type } = allModifyDynamicResArray[0] || {}; if (type === 1 && origin_type !== 8) { - await randomDynamic(num) + await randomDynamic(num); } else { log.info('随机动态', '已有非抽奖动态故无需创建'); } @@ -36,16 +36,16 @@ function start(num) { let times = utils.counter(); /* 注册事件 */ event_bus.on('Turn_on_the_Monitor', async () => { - const lotterys = global_var.get("Lottery"); + const lotterys = global_var.get('Lottery'); if (lotterys.length === 0) { log.info('抽奖', '抽奖信息为空'); - event_bus.emit('Turn_off_the_Monitor', '抽奖信息为空') + event_bus.emit('Turn_off_the_Monitor', '抽奖信息为空'); return; } if (times.value() === lotterys.length) { log.info('抽奖', '所有动态转发完毕'); times.clear(); - event_bus.emit('Turn_off_the_Monitor', '目前无抽奖信息,过一会儿再来看看吧') + event_bus.emit('Turn_off_the_Monitor', '目前无抽奖信息,过一会儿再来看看吧'); return; } const lottery = lotterys[times.next()]; @@ -63,10 +63,10 @@ function start(num) { await createRandomDynamic(config.create_dy_num); event_bus.flush(); resolve(); - }) + }); event_bus.emit('Turn_on_the_Monitor'); }); } -module.exports = { start } \ No newline at end of file +module.exports = { start }; \ No newline at end of file diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index f93f8ff665..0133046d3c 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -30,13 +30,13 @@ module.exports = Object.freeze({ SHORTLINK: 'https://b23.tv/{{short_id}}', SPACE_MYINFO: 'https://api.bilibili.com/x/space/myinfo', TAG_INFO: 'https://api.bilibili.com/x/tag/info', - TOP_FEED_RCMD: "https://api.bilibili.com/x/web-interface/index/top/feed/rcmd", - TOP_RCMD: "https://api.bilibili.com/x/web-interface/index/top/rcmd", + TOP_FEED_RCMD: 'https://api.bilibili.com/x/web-interface/index/top/feed/rcmd', + TOP_RCMD: 'https://api.bilibili.com/x/web-interface/index/top/rcmd', TOPIC_SVR_TOPIC_HISTORY: 'https://api.vc.bilibili.com/topic_svr/v1/topic_svr/topic_history', TOPIC_SVR_TOPIC_NEW: 'https://api.vc.bilibili.com/topic_svr/v1/topic_svr/topic_new', - V2_REPLAY: "https://api.bilibili.com/x/v2/reply", + V2_REPLAY: 'https://api.bilibili.com/x/v2/reply', WEB_INTERFACE_CARD: 'https://api.bilibili.com/x/web-interface/card', - WEB_INTERFACE_NAV_STAT: "https://api.bilibili.com/x/web-interface/nav/stat", + WEB_INTERFACE_NAV_STAT: 'https://api.bilibili.com/x/web-interface/nav/stat', WEB_INTERFACE_SEARCH_TYPE: 'https://api.bilibili.com/x/web-interface/search/type', X_POLYMER_WEB_DYNAMIC_V1_DETAIL: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/detail', -}) +}); diff --git a/lib/net/bili.js b/lib/net/bili.js index 261da42fac..7273a9f228 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -14,15 +14,15 @@ class Line { * @param {(responseText: string) => ResResult} [pub_handler] */ constructor(line_name, requests, pub_handler) { - this.line_name = line_name - this.requests = requests - this.valid_line = 0 - this.switch_times = 0 - if (pub_handler) this.pub_handler = pub_handler + this.line_name = line_name; + this.requests = requests; + this.valid_line = 0; + this.switch_times = 0; + if (pub_handler) this.pub_handler = pub_handler; /** * @type {ResResult} */ - this.res_result = [false, null, ''] + this.res_result = [false, null, '']; } /** @@ -30,13 +30,13 @@ class Line { * @returns {boolean} */ switchLine() { - const { valid_line, requests: { length }, switch_times } = this - this.valid_line = (valid_line + 1) % length - this.switch_times += 1 + const { valid_line, requests: { length }, switch_times } = this; + this.valid_line = (valid_line + 1) % length; + this.switch_times += 1; if (switch_times > length) { - return false + return false; } else { - return true + return true; } } @@ -45,8 +45,8 @@ class Line { * @param {number} line */ storeLine(line) { - this.valid_line = line - this.switch_times = 0 + this.valid_line = line; + this.switch_times = 0; } /** @@ -59,24 +59,24 @@ class Line { { line_name, requests, valid_line } = this, resp = await requests[valid_line](...args); if (typeof resp === 'string') { - this.res_result = this.pub_handler(resp) + this.res_result = this.pub_handler(resp); } else { - this.res_result = resp + this.res_result = resp; } - const [i_switch, value, msg] = this.res_result + const [i_switch, value, msg] = this.res_result; if (!i_switch) { - log.info(line_name, msg) - this.storeLine(valid_line) - return value + log.info(line_name, msg); + this.storeLine(valid_line); + return value; } if (this.switchLine()) { - log.warn(line_name, msg) - log.warn(line_name, `切换线路(${valid_line + 1}/${requests.length})`) - return await this.run() + log.warn(line_name, msg); + log.warn(line_name, `切换线路(${valid_line + 1}/${requests.length})`); + return await this.run(); } else { - log.error(line_name, msg) - log.error(line_name, '所有备用线路均连接失败') - return value + log.error(line_name, msg); + log.error(line_name, '所有备用线路均连接失败'); + return value; } } } @@ -93,15 +93,15 @@ function get({ url, config, contents, query }) { method: 'GET', config, headers: { - "accept": 'application/json, text/plain, */*', - "cookie": GlobalVar.get("cookie") + 'accept': 'application/json, text/plain, */*', + 'cookie': GlobalVar.get('cookie') }, query, contents, success: res => resolve(res.body), failure: err => resolve(err) - }) - }) + }); + }); } /** @@ -116,16 +116,16 @@ function post({ url, config, contents, query }) { method: 'POST', config, headers: { - "accept": 'application/json, text/plain, */*', - "content-type": 'application/x-www-form-urlencoded; charset=UTF-8', - "cookie": GlobalVar.get("cookie") + 'accept': 'application/json, text/plain, */*', + 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', + 'cookie': GlobalVar.get('cookie') }, query, contents, success: res => resolve(res.body), failure: err => resolve(err) - }) - }) + }); + }); } /** @@ -143,7 +143,7 @@ const bili_client = { }), res = strToJson(responseText); if (res.code === 0) { - GlobalVar.set("myUNAME", res.data.name) + GlobalVar.set('myUNAME', res.data.name); return res.data; } else { return null; @@ -212,7 +212,7 @@ const bili_client = { }), res = strToJson(responseText); if (res.code === 0) { - log.info('获取未读信息', `成功`); + log.info('获取未读信息', '成功'); return res.data; } else { log.error('获取未读信息', `失败\n${responseText}`); @@ -243,11 +243,11 @@ const bili_client = { source: it.item.source_content, uri: it.item.uri, timestamp: it.reply_time - } + }; }); } else { log.error('获取一页回复', '失败'); - return [] + return []; } }, /** @@ -292,7 +292,7 @@ const bili_client = { }); return { has_more, data }; } else if (res.code === 2) { - log.error('获取私信', `API抽风...请再次尝试`); + log.error('获取私信', 'API抽风...请再次尝试'); return { has_more: 0, data: [] }; } else { log.error('获取私信', `失败\n${responseText}`); @@ -316,16 +316,16 @@ const bili_client = { }), res = strToJson(responseText); if (res.code === 0) { - const msgs = res.data.messages + const msgs = res.data.messages; if (msgs instanceof Array) { - log.info('私信细节', `${talker_id}有${size}条未读私信`) - return msgs.filter(it => ![5, 8, 9, 10, 11].includes(it.msg_source)).map(it => it.content).join('\n') + log.info('私信细节', `${talker_id}有${size}条未读私信`); + return msgs.filter(it => ![5, 8, 9, 10, 11].includes(it.msg_source)).map(it => it.content).join('\n'); } else { - log.warn('私信细节', `${talker_id}无私信`) + log.warn('私信细节', `${talker_id}无私信`); } } - log.error('私信细节', `获取失败`) - return '' + log.error('私信细节', '获取失败'); + return ''; }, /** * 获取未读私信数量 @@ -363,8 +363,8 @@ const bili_client = { talker_id, session_type, ack_seqno: msg_seqno, - csrf_token: GlobalVar.get("csrf"), - csrf: GlobalVar.get("csrf") + csrf_token: GlobalVar.get('csrf'), + csrf: GlobalVar.get('csrf') } }), res = strToJson(responseText); @@ -408,9 +408,9 @@ const bili_client = { } }).then(a => { const dyid = (a.match(/[0-9]{18}/) || [])[0]; - log.info("短连接转换", `${short_id} -> ${dyid}`) - return dyid - }) + log.info('短连接转换', `${short_id} -> ${dyid}`); + return dyid; + }); }, _getOneDynamicByDyid: new Line( '获取一个动态的细节', @@ -436,9 +436,9 @@ const bili_client = { { code, data } = res; switch (code) { case 0: - return [false, data, `ok`]; + return [false, data, 'ok']; default: - return [true, undefined, `获取动态数据出错:\n${responseText}`] + return [true, undefined, `获取动态数据出错:\n${responseText}`]; } }), /** @@ -447,7 +447,7 @@ const bili_client = { * @return {Promise} 失败返回undefined */ async getOneDynamicByDyid(dynamic_id) { - return this._getOneDynamicByDyid.run(dynamic_id) + return this._getOneDynamicByDyid.run(dynamic_id); }, /** * 获取一组动态的信息 @@ -460,14 +460,14 @@ const bili_client = { return get({ url: API.DYNAMIC_SVR_SPACE_HISTORY, query: { - visitor_uid: GlobalVar.get("myUID"), + visitor_uid: GlobalVar.get('myUID'), host_uid, offset_dynamic_id, }, config: { retry: false } - }) + }); }, /** * 通过tag名获取tag的id @@ -504,7 +504,7 @@ const bili_client = { query: { topic_id: tagid } - }) + }); }, /** * 获取tag下的最新动态 @@ -522,7 +522,7 @@ const bili_client = { config: { retry: false } - }) + }); }, /** * 搜索专栏 @@ -549,7 +549,7 @@ const bili_client = { return { pub_time: it.pub_time, id: it.id - } + }; }); } catch (error) { log.error('搜索专栏', '失败 原因:\n' + responseText); @@ -569,7 +569,7 @@ const bili_client = { getOneArticleByCv(cv) { return get({ url: API.READ_CV.replace('{{cv}}', cv) - }) + }); }, /** * 获取粉丝数的所有有效方式 @@ -607,7 +607,7 @@ const bili_client = { * @returns {Promise} */ (uid) => get({ - url: "https://tenapi.cn/bilibilifo/", + url: 'https://tenapi.cn/bilibilifo/', query: { uid } @@ -617,7 +617,7 @@ const bili_client = { if (res.code === 0) { return [false, res.data.follower, 'ok']; } else { - return [true, -1, `出错 可能是访问过频繁\n${responseText}`] + return [true, -1, `出错 可能是访问过频繁\n${responseText}`]; } }), /** @@ -626,7 +626,7 @@ const bili_client = { * @returns {Promise} */ getUserInfo(uid) { - return this._getUserInfo.run(uid) + return this._getUserInfo.run(uid); }, /** * 获取开奖信息 @@ -672,7 +672,7 @@ const bili_client = { fid: uid, act: 1, re_src: 0, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), (uid) => post({ @@ -680,7 +680,7 @@ const bili_client = { contents: { type: 1, follow: uid, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), (uid) => post({ @@ -689,26 +689,26 @@ const bili_client = { fids: uid, act: 1, re_src: 1, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }) ], responseText => { const res = strToJson(responseText); switch (res.code) { case 0: - return [false, 0, '关注+1'] + return [false, 0, '关注+1']; case 22002: - return [false, 2, '您已被对方拉入黑名单'] + return [false, 2, '您已被对方拉入黑名单']; case 22003: - return [false, 3, '黑名单用户无法关注'] + return [false, 3, '黑名单用户无法关注']; case 22015: - return [false, 4, '账号异常'] + return [false, 4, '账号异常']; case 22009: - return [false, 5, '关注已达上限'] + return [false, 5, '关注已达上限']; case 22014: - return [false, 6, '已经关注用户,无法重复关注'] + return [false, 6, '已经关注用户,无法重复关注']; default: - return [true, 1, `未知错误\n${responseText}`] + return [true, 1, `未知错误\n${responseText}`]; } }), /** @@ -727,7 +727,7 @@ const bili_client = { * - 已经关注用户 6 */ autoAttention(uid) { - return this._autoAttention.run(uid) + return this._autoAttention.run(uid); }, /** * 移动分区 @@ -743,7 +743,7 @@ const bili_client = { contents: { fids: uid, tagids: tagid, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }); /* 重复移动code also equal 0 */ @@ -771,7 +771,7 @@ const bili_client = { fid: uid, act: 2, re_src: 0, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), res = strToJson(responseText); @@ -799,10 +799,10 @@ const bili_client = { responseText = await post({ url: API.DYNAMIC_LIKE_THUMB, contents: { - uid: GlobalVar.get("myUID"), + uid: GlobalVar.get('myUID'), dynamic_id: dyid, up: 1, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), res = strToJson(responseText); @@ -845,7 +845,7 @@ const bili_client = { async autoRelay(uid, dyid, msg = '转发动态', ctrl = '[]') { const len = msg.length; if (len > 233) { - msg = msg.slice(0, 233 - len) + msg = msg.slice(0, 233 - len); } const responseText = await post({ @@ -858,7 +858,7 @@ const bili_client = { dynamic_id: dyid, content: msg, ctrl, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), res = strToJson(responseText); @@ -890,9 +890,9 @@ const bili_client = { responseText = await post({ url: API.DYNAMIC_MIX_RESERVE_ATTACH_CARD_BUTTON, contents: { - cur_btn_status: "1", + cur_btn_status: '1', reserve_id, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), res = strToJson(responseText); @@ -920,25 +920,25 @@ const bili_client = { async createDynamic(content) { let contents = { - csrf: GlobalVar.get("csrf"), + csrf: GlobalVar.get('csrf'), extension: '{"emoji_type":1,"from":{"emoji_type":1},"flag_cfg":{}}', }, url = ''; if (content instanceof Array) { - url = API.DYNAMIC_SVR_CREATE_DRAW + url = API.DYNAMIC_SVR_CREATE_DRAW; contents = { ...contents, biz: 3, category: 3, pictures: JSON.stringify(content) - } + }; } else { - url = API.DYNAMIC_SVR_CREATE + url = API.DYNAMIC_SVR_CREATE; contents = { ...contents, type: 4, content, - } + }; } const responseText = await post({ url, @@ -946,10 +946,10 @@ const bili_client = { }); if (/^{"code":0/.test(responseText)) { log.info('发布动态', `成功创建一条随机内容的动态\n${JSON.stringify(content)}\n`); - return false + return false; } else { log.error('发布动态', `发布动态失败\n${JSON.stringify(content)}\n${responseText}`); - return true + return true; } }, _getTopRcmd: new Line('获取推荐', [ @@ -964,7 +964,7 @@ const bili_client = { if (res.code === 0) { return [false, res.data.item.map(it => { return [it.owner.mid, it.id]; - }), "成功"]; + }), '成功']; } else { return [true, [], `获取推荐失败\n${responseText}`]; } @@ -974,7 +974,7 @@ const bili_client = { * @returns {Promise>} */ async getTopRcmd() { - return this._getTopRcmd.run() + return this._getTopRcmd.run(); }, /** * 分享视频 @@ -987,26 +987,26 @@ const bili_client = { responseText = await post({ url: API.DYNAMIC_REPOST_SHARE, contents: { - platform: "pc", + platform: 'pc', uid, type: 8, - content: "分享视频", + content: '分享视频', repost_code: 20000, rid: aid, - csrf_token: GlobalVar.get("csrf") + csrf_token: GlobalVar.get('csrf') } }), res = strToJson(responseText); switch (res.code) { case 0: log.info('转发视频', `成功转发视频(av${aid})`); - return false + return false; case 1101015: log.warn('转发视频', `该动态不能转发分享(av${aid})`); - return false + return false; default: log.error('转发视频', `转发失败\n${responseText}`); - return true + return true; } }, /** @@ -1019,7 +1019,7 @@ const bili_client = { url: API.DYNAMIC_SVR_RM_DYNAMIC, contents: { dynamic_id: dyid, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') }, config: { retry: false @@ -1067,7 +1067,7 @@ const bili_client = { type: type, message: msg, code, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), res = strToJson(responseText); @@ -1085,7 +1085,7 @@ const bili_client = { log.error('自动评论', '需要输入验证码'); return res.data.url; case 12035: - log.error('自动评论', `已被对方拉入黑名单`); + log.error('自动评论', '已被对方拉入黑名单'); return 5; case 12053: log.error('自动评论', '黑名单用户无法互动'); @@ -1139,13 +1139,13 @@ const bili_client = { */ async sendChatWithOcr(rid, msg, type) { let need_captcha = false; - let url = ""; + let url = ''; let status = 0; do { if (need_captcha) { const code = await ocr(url); if (code) { - log.info("验证码识别", `${url} -> ${code}`); + log.info('验证码识别', `${url} -> ${code}`); status = await bili_client.sendChat( rid, msg, @@ -1153,11 +1153,11 @@ const bili_client = { code ); if (status === 0) { - need_captcha = false + need_captcha = false; } else if (status === 12) { - need_captcha = true + need_captcha = true; } else { - need_captcha = false + need_captcha = false; } } } else { @@ -1165,12 +1165,12 @@ const bili_client = { rid, msg, type - ) - if (typeof url === "string" - && hasEnv("ENABLE_CHAT_CAPTCHA_OCR")) { - need_captcha = true + ); + if (typeof url === 'string' + && hasEnv('ENABLE_CHAT_CAPTCHA_OCR')) { + need_captcha = true; } else { - status = url + status = url; } } } while (need_captcha); @@ -1194,14 +1194,14 @@ const bili_client = { res = strToJson(responseText); switch (res.code) { case 0: - log.info('查询评论', `成功`); + log.info('查询评论', '成功'); try { const upmid = res.data.upper.mid; return res.data.replies .filter(it => it.mid !== upmid) .map(it => [it.member.uname, it.content.message]); } catch (_) { - return [] + return []; } default: log.error('查询评论', `未知错误\n${responseText}`); @@ -1216,7 +1216,7 @@ const bili_client = { * @returns {Promise} */ async checkMyPartition(name) { - if (!name) name = '此处存放因抽奖临时关注的up' + if (!name) name = '此处存放因抽奖临时关注的up'; const responseText = await get({ url: API.RELATION_TAGS @@ -1256,7 +1256,7 @@ const bili_client = { url: API.RELATION_TAG_CREATE, contents: { tag: partition_name, - csrf: GlobalVar.get("csrf") + csrf: GlobalVar.get('csrf') } }), obj = strToJson(responseText); @@ -1281,7 +1281,7 @@ const bili_client = { responseText = await get({ url: API.RELATION_TAG, query: { - mid: GlobalVar.get("myUID"), + mid: GlobalVar.get('myUID'), tagid: tagid, pn: n, ps: 50 @@ -1303,4 +1303,4 @@ const bili_client = { }; -module.exports = bili_client +module.exports = bili_client; diff --git a/lib/net/http.js b/lib/net/http.js index 9b43559c74..0acd22c5fc 100644 --- a/lib/net/http.js +++ b/lib/net/http.js @@ -69,7 +69,7 @@ function send(detail) { const { method, url, stream, config, proxy, query, contents, headers, success, failure } = detail; const { timeout, wait, retry, redirect, retry_times } = config; const thisURL = new URL(url) - , content = formatContents(headers["content-type"], contents) + , content = formatContents(headers['content-type'], contents) , request = (thisURL.protocol === 'https:') ? https_request : http_request; /** * @type {import("https").RequestOptions} @@ -82,10 +82,10 @@ function send(detail) { path: thisURL.pathname + thisURL.search + thisURL.hash, headers, }; - if (!headers["user-agent"]) options.headers["user-agent"] = DEFAULT_UA; + if (!headers['user-agent']) options.headers['user-agent'] = DEFAULT_UA; if (query) options.path += (thisURL.search ? '&' : '?') + stringify(query); if (content) { - if (!headers["content-type"]) options.headers["content-type"] = DEFAULT_CONTENT_TYPE; + if (!headers['content-type']) options.headers['content-type'] = DEFAULT_CONTENT_TYPE; options.headers['content-length'] = Buffer.byteLength(content, 'utf-8').toString(); } if (proxy) { @@ -93,28 +93,28 @@ function send(detail) { ? new HttpsProxyAgent(proxy.url) : new HttpProxyAgent(proxy.url); for (const ah of proxy.auth_headers) { - options.headers[ah[0]] = ah[1] + options.headers[ah[0]] = ah[1]; } - options.rejectUnauthorized = false + options.rejectUnauthorized = false; } const req = request(options, res => { let protodata = ''; const { statusCode, headers } = res; if (redirect && ~~(statusCode / 100) === 3) { try { - detail.url = new URL(headers.location).href + detail.url = new URL(headers.location).href; } catch (error) { - detail.url = new URL(thisURL.origin + headers.location).href + detail.url = new URL(thisURL.origin + headers.location).href; } console.log(`[重定向]状态码:${statusCode} location:${detail.url}`); - send(detail) - return + send(detail); + return; } if (stream) { - success({ headers: headers, resStream: res }) + success({ headers: headers, resStream: res }); } else { res.setEncoding(DEFAULT_DECODE) - .on('data', chunk => { protodata += chunk }) + .on('data', chunk => { protodata += chunk; }) .on('error', async err => { if (retry && retry_times) { console.log(`[不期待响应]原因:${err.message} 尝试重新请求中...`); @@ -122,18 +122,18 @@ function send(detail) { detail.config.retry_times = retry_times - 1; send(detail); } else { - failure(`[响应错误]${err.message} 响应数据:\n${protodata}`) + failure(`[响应错误]${err.message} 响应数据:\n${protodata}`); } }) .on('end', () => { if (statusCode < 400) { - success({ headers: headers, body: protodata }) + success({ headers: headers, body: protodata }); } else { - res.emit('error', new Error(`HTTP状态码: ${statusCode}`)) + res.emit('error', new Error(`HTTP状态码: ${statusCode}`)); } - }) + }); } - }) + }); req.on('error', async err => { if (retry && retry_times) { console.log(`[请求失败]原因:${err.message} 尝试重新连接中...`); @@ -143,9 +143,9 @@ function send(detail) { } else { failure(`[请求失败]: ${err.message}`); } - }) - req.on('timeout', () => { req.destroy(new Error('请求超时')) }) - req.end(content) + }); + req.on('timeout', () => { req.destroy(new Error('请求超时')); }); + req.end(content); } /** @@ -173,10 +173,10 @@ function setDefault(detail) { stream: false, proxy: '', headers: {}, - success: (res) => { console.log(res.headers) }, - failure: (err) => { console.log(err) }, + success: (res) => { console.log(res.headers); }, + failure: (err) => { console.log(err); }, ...detail - } + }; detail.config = { timeout: DEFAULT_TIMEOUT, wait: DEFAULT_WAIT, @@ -184,7 +184,7 @@ function setDefault(detail) { redirect: DEFAULT_REDIRECT, retry_times: DEFAULT_RETRY_TIMES, ...detail.config - } + }; return detail; } @@ -202,4 +202,4 @@ function delay(time) { } -module.exports = { send } \ No newline at end of file +module.exports = { send }; \ No newline at end of file diff --git a/lib/update.js b/lib/update.js index 65364629df..4932844faf 100644 --- a/lib/update.js +++ b/lib/update.js @@ -1,6 +1,6 @@ -const { send } = require('./net/http') -const { strToJson, download, try_for_each } = require('./utils') -const { version, checkVersion, log } = require('./utils') +const { send } = require('./net/http'); +const { strToJson, download, try_for_each } = require('./utils'); +const { version, checkVersion, log } = require('./utils'); const platform = new Map([ @@ -25,7 +25,7 @@ function getLatestRelease(owner, repo) { send({ url: `https://api.github.com/repos/${owner}/${repo}/releases/latest`, headers: { - "accept": 'application/vnd.github.v3+json' + 'accept': 'application/vnd.github.v3+json' }, config: { retry: false @@ -33,15 +33,15 @@ function getLatestRelease(owner, repo) { success: ({ body }) => { const release = strToJson(body); if (release.tag_name) { - resolve(release) + resolve(release); } else { - reject(body) + reject(body); } }, failure: error => { - reject(error) + reject(error); } - }) + }); }); } @@ -51,7 +51,7 @@ function getLatestRelease(owner, repo) { */ function checkPlatform(releases) { return releases.includes(platform) - && releases.includes(arch) + && releases.includes(arch); } /** @@ -60,40 +60,40 @@ function checkPlatform(releases) { */ async function update(isDdownload) { try { - const { tag_name, assets, body: text } = await getLatestRelease('shanmiteko', 'LotteryAutoScript') + const { tag_name, assets, body: text } = await getLatestRelease('shanmiteko', 'LotteryAutoScript'); if (checkVersion(version) < checkVersion(tag_name)) { const download_url = assets .filter(({ name }) => checkPlatform(name)) - .map(({ browser_download_url }) => browser_download_url) + .map(({ browser_download_url }) => browser_download_url); if (download_url.length) { if (isDdownload) { await try_for_each(download_url.entries(), async ([i, url]) => { - let proxy_url = "https://mirror.ghproxy.com/"; - proxy_url += url - log.warn('自动下载', `切换代理${proxy_url}`) + let proxy_url = 'https://mirror.ghproxy.com/'; + proxy_url += url; + log.warn('自动下载', `切换代理${proxy_url}`); await download(proxy_url, `latest_version${i}.zip`) .catch(async err => { - log.error('自动下载', err) - proxy_url = url - log.warn('自动下载', `使用原始链接${proxy_url}`) - await download(proxy_url, `latest_version${i}.zip`) - }) - return false - }) - log.info('自动下载', '成功下载到当前目录') + log.error('自动下载', err); + proxy_url = url; + log.warn('自动下载', `使用原始链接${proxy_url}`); + await download(proxy_url, `latest_version${i}.zip`); + }); + return false; + }); + log.info('自动下载', '成功下载到当前目录'); log.info('检查更新', '请手动解压替换可执行文件'); } - log.info('更新说明', '\n' + text + '\n') + log.info('更新说明', '\n' + text + '\n'); } else { - throw `未找到能在此平台(${process.platform})-(${process.arch})上运行的版本,建议以源码运行` + throw `未找到能在此平台(${process.platform})-(${process.arch})上运行的版本,建议以源码运行`; } } else { - throw '当前已是最新版本' + throw '当前已是最新版本'; } } catch (error) { - log.warn('更新脚本', error) + log.warn('更新脚本', error); } } -module.exports = { update } \ No newline at end of file +module.exports = { update }; \ No newline at end of file diff --git a/lib/utils.js b/lib/utils.js index d32d4fdfed..5f92b9b944 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,7 +1,7 @@ const chalk = require('chalk'); const fs = require('fs'); const path = require('path'); -const { send } = require("./net/http"); +const { send } = require('./net/http'); const { version } = require('../package.json'); /** @@ -10,15 +10,15 @@ const { version } = require('../package.json'); const utils = { version, /**环境变量设置文件 */ - env_file: path.join(process.cwd(), "env.js"), + env_file: path.join(process.cwd(), 'env.js'), /**配置文件 */ - config_file: path.join(process.cwd(), "my_config.js"), + config_file: path.join(process.cwd(), 'my_config.js'), /**dyids存放目录 */ - dyids_dir: path.join(process.cwd(), "dyids"), + dyids_dir: path.join(process.cwd(), 'dyids'), /**lottery_info存放目录 */ - lottery_info_dir: path.join(process.cwd(), "lottery_info"), + lottery_info_dir: path.join(process.cwd(), 'lottery_info'), /**本地抽奖信息存放目录 */ - lottery_dyids: path.join(process.cwd(), "lottery_dyids"), + lottery_dyids: path.join(process.cwd(), 'lottery_dyids'), /**dyid长度 */ dyid_length: 18, /** @@ -29,7 +29,7 @@ const utils = { * @returns {Number} */ checkVersion(version) { - return (version.match(/\d.*/)[0]).split('.').reduce((a, v, i) => a + (0.01 ** i) * Number(v), 0) + return (version.match(/\d.*/)[0]).split('.').reduce((a, v, i) => a + (0.01 ** i) * Number(v), 0); }, /** * 安全的将JSON字符串转为对象 @@ -43,16 +43,16 @@ const utils = { if (typeof str === 'string') { try { const obj = JSON.parse(str); - return typeof obj === 'object' ? obj : false + return typeof obj === 'object' ? obj : false; } catch (e) { - utils.log.error("json解析", e + "\n" + params) + utils.log.error('json解析', e + '\n' + params); return false; } } else { return false; } })(params); - return isJSON ? isJSON : {} + return isJSON ? isJSON : {}; }, /** * @template T @@ -61,7 +61,7 @@ const utils = { */ async try_for_each(iter, fn) { for (const item of iter) { - if (await fn(item)) break + if (await fn(item)) break; } }, /** @@ -74,12 +74,12 @@ const utils = { async retryfn(max_times, unexpected, fn) { let ret = null; for (let times = 0; times < max_times; times++) { - ret = await fn() + ret = await fn(); if (unexpected.includes(ret)) { - utils.log.warn('自动重试', `将在 ${times + 1} 分钟后再次尝试(${times + 1}/${max_times})`) - await utils.delay(60 * 1000 * (times + 1)) + utils.log.warn('自动重试', `将在 ${times + 1} 分钟后再次尝试(${times + 1}/${max_times})`); + await utils.delay(60 * 1000 * (times + 1)); } else { - break + break; } } return ret; @@ -123,10 +123,10 @@ const utils = { let c = { i: 0, next: () => c.i++, - clear: () => { c.i = 0 }, + clear: () => { c.i = 0; }, value: () => c.i - } - return c + }; + return c; }, /** * 无限序列 @@ -134,7 +134,7 @@ const utils = { */ *infiniteNumber() { for (let index = 0; ; index++) { - yield index + yield index; } }, /** @@ -148,7 +148,7 @@ const utils = { if (Array.isArray(arr) && arr.length) { RandomOne = arr[parseInt(Math.random() * arr.length)]; } - return RandomOne + return RandomOne; }, /** * Fisher–Yates shuffle洗牌 @@ -173,9 +173,9 @@ const utils = { return key_words.reduce((acc, word) => { word.startsWith('~') ? RegExp(word.slice(1)).test(text) && (acc = false) - : RegExp(word).test(text) && (acc = true) - return acc - }, false) + : RegExp(word).test(text) && (acc = true); + return acc; + }, false); }, /** * 是否有指定环境变量 @@ -207,16 +207,16 @@ const utils = { */ proPrint(msg, split = ' ') { if (msg instanceof Array) { - msg = msg.join(split) + msg = msg.join(split); } - console.log(msg) + console.log(msg); }, /** * @param {Array} msg * @returns */ rainbow(msg) { - this.proPrint(msg.map(it => it.split('').map(l => chalk.hex("#89cff0")(l)).join('')), '\n') + this.proPrint(msg.map(it => it.split('').map(l => chalk.hex('#89cff0')(l)).join('')), '\n'); }, /** * @param {number} done @@ -226,55 +226,55 @@ const utils = { progress_bar(done, total, size = 30) { let perc = done >= total ? 1 : done / total, bar = ~~(perc * size), - status_bar = `\r[${"=".repeat(bar) + ">" + " ".repeat(size - bar)}] ${(perc * 100 + ' ').slice(0, 4)}%` - process.stdout.write(status_bar) + status_bar = `\r[${'='.repeat(bar) + '>' + ' '.repeat(size - bar)}] ${(perc * 100 + ' ').slice(0, 4)}%`; + process.stdout.write(status_bar); }, debug(context, msg) { if (this._level > 3) { if (msg instanceof Object) msg = JSON.stringify(msg, null, 4); let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], - [this._colors[1], "[Debug]"], - [this._colors[2], `[帐号${process.env["NUMBER"]} ${context}]`], + [this._colors[1], '[Debug]'], + [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], [this._colors[3], `[\n${msg}\n]`], ]; - this.proPrint(color_text_pair.map(([color, text]) => color(text))) + this.proPrint(color_text_pair.map(([color, text]) => color(text))); } }, info(context, msg) { if (this._level > 2) { let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], - [this._colors[1], "[Info]"], - [this._colors[2], `[帐号${process.env["NUMBER"]} ${context}]`], + [this._colors[1], '[Info]'], + [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], [this._colors[4], `[${msg}]`], ]; this._cache.push(color_text_pair.map(it => it[1]).join(' ')); - this.proPrint(color_text_pair.map(([color, text]) => color(text))) + this.proPrint(color_text_pair.map(([color, text]) => color(text))); } }, warn(context, msg) { if (this._level > 1) { let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], - [this._colors[1], "[Warn]"], - [this._colors[2], `[帐号${process.env["NUMBER"]} ${context}]`], + [this._colors[1], '[Warn]'], + [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], [this._colors[5], `[\n${msg}\n]`], ]; this._cache.push(color_text_pair.map(it => it[1]).join(' ')); - this.proPrint(color_text_pair.map(([color, text]) => color(text))) + this.proPrint(color_text_pair.map(([color, text]) => color(text))); } }, error(context, msg) { if (this._level > 0) { let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], - [this._colors[1], "[Error]"], - [this._colors[2], `[帐号${process.env["NUMBER"]} ${context}]`], + [this._colors[1], '[Error]'], + [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], [this._colors[6], `[\n${msg}\n]`], ]; this._cache.push(color_text_pair.map(it => it[1]).join(' ')); - this.proPrint(color_text_pair.map(([color, text]) => color(text))) + this.proPrint(color_text_pair.map(([color, text]) => color(text))); } } }, @@ -287,19 +287,19 @@ const utils = { return new Promise((resolve) => { send({ method: 'POST', - url: process.env["CHAT_CAPTCHA_OCR_URL"] || "http://127.0.0.1:9898/ocr/url/text", + url: process.env['CHAT_CAPTCHA_OCR_URL'] || 'http://127.0.0.1:9898/ocr/url/text', headers: { - "content-type": 'application/x-www-form-urlencoded; charset=UTF-8', + 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', }, contents: { url }, success: res => { - resolve(res.body) + resolve(res.body); }, failure: () => { - resolve() + resolve(); } - }) - }) + }); + }); }, /** * 下载文件 @@ -317,26 +317,26 @@ const utils = { retry: false }, success: ({ headers, resStream }) => { - const total_len = Number(headers["content-length"]) || 16000000; + const total_len = Number(headers['content-length']) || 16000000; let recv_length = 0; const wtbs = fs.createWriteStream(file_name); resStream.on('data', chuck => { - recv_length += chuck.length - utils.log.progress_bar(recv_length, total_len) - }) - resStream.pipe(wtbs) + recv_length += chuck.length; + utils.log.progress_bar(recv_length, total_len); + }); + resStream.pipe(wtbs); wtbs.on('finish', () => { - utils.log.proPrint('下载完成') - resolve() + utils.log.proPrint('下载完成'); + resolve(); }).on('error', error => { - wtbs.destroy() - reject(error) - }) + wtbs.destroy(); + reject(error); + }); }, failure: error => { - reject(error) + reject(error); } - }) + }); }); }, /** @@ -346,11 +346,11 @@ const utils = { */ hasFileOrDir(path) { try { - fs.accessSync(path, fs.constants.F_OK) + fs.accessSync(path, fs.constants.F_OK); } catch (_) { - return false + return false; } - return true + return true; }, /** * 生成文件夹 @@ -361,10 +361,10 @@ const utils = { return new Promise((resolve) => { fs.stat(dirname, (err) => { if (err) { - fs.mkdirSync(dirname) + fs.mkdirSync(dirname); } - resolve() - }) + resolve(); + }); }); }, /** @@ -381,18 +381,18 @@ const utils = { return new Promise((resolve, rejects) => { fs.open(fpath, flag, (err, fd) => { if (err) { - rejects(err) + rejects(err); } else { fs.write(fd, buffer, 0, buffer.length, 0, err => { - fs.close(fd) + fs.close(fd); if (err) { - rejects(err) + rejects(err); } else { resolve(); } - }) + }); } - }) + }); }); }, /** @@ -402,7 +402,7 @@ const utils = { */ readDyidFile(num) { const fpath = num < 2 ? path.join(utils.dyids_dir, 'dyid.txt') : path.join(utils.dyids_dir, `dyid${num}.txt`); - return fs.createReadStream(fpath, { encoding: 'utf8', highWaterMark: (utils.dyid_length + 1) * 1000 }) + return fs.createReadStream(fpath, { encoding: 'utf8', highWaterMark: (utils.dyid_length + 1) * 1000 }); }, /** * 追加dyid @@ -411,7 +411,7 @@ const utils = { */ writeDyidFile(num) { const fpath = num < 2 ? path.join(utils.dyids_dir, 'dyid.txt') : path.join(utils.dyids_dir, `dyid${num}.txt`); - return fs.createWriteStream(fpath, { flags: 'a' }) + return fs.createWriteStream(fpath, { flags: 'a' }); }, /** * 追加lotteryinfo @@ -422,17 +422,17 @@ const utils = { async appendLotteryInfoFile(from, lottery_info) { let all_lottery_info = {}; try { - all_lottery_info = utils.strToJson(fs.readFileSync(path.join(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`)).toString()) + all_lottery_info = utils.strToJson(fs.readFileSync(path.join(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`)).toString()); } catch (_) { - all_lottery_info = {} + all_lottery_info = {}; } await utils.createDir(utils.lottery_info_dir); if (all_lottery_info[from] instanceof Array) { - all_lottery_info[from].push(...lottery_info) + all_lottery_info[from].push(...lottery_info); } else { - all_lottery_info[from] = lottery_info + all_lottery_info[from] = lottery_info; } - await utils.createFile(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`, JSON.stringify(all_lottery_info), "w") + await utils.createFile(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`, JSON.stringify(all_lottery_info), 'w'); }, /** * 读取lottery_info @@ -443,12 +443,12 @@ const utils = { return new Promise((resolve) => { fs.readFile(path.join(utils.lottery_info_dir, filename), (err, data) => { if (err) { - resolve([]) + resolve([]); } else { let all_lottery_info = utils.strToJson(data.toString('utf8')); - resolve(Object.values(all_lottery_info).flat()) + resolve(Object.values(all_lottery_info).flat()); } - }) + }); }); }, /** @@ -456,7 +456,7 @@ const utils = { */ async clearLotteryInfo() { await utils.createDir(utils.lottery_info_dir); - await utils.createFile(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`, "{}", "w") + await utils.createFile(utils.lottery_info_dir, `lottery_info_${Number(process.env.NUMBER)}.json`, '{}', 'w'); }, /** * 获取含抽奖dyids @@ -467,11 +467,11 @@ const utils = { return new Promise((resolve) => { fs.readFile(path.join(utils.lottery_dyids, filename), (err, data) => { if (err) { - resolve([]) + resolve([]); } else { - resolve(data.toString("utf8").split(/[^0123456789]+/)) + resolve(data.toString('utf8').split(/[^0123456789]+/)); } - }) + }); }); } }; diff --git a/main.js b/main.js index 989b5c5b8c..86556234c5 100644 --- a/main.js +++ b/main.js @@ -1,24 +1,24 @@ -const { version: ve, env_file, config_file, log, hasEnv, delay, hasFileOrDir, clearLotteryInfo } = require("./lib/utils"); +const { version: ve, env_file, config_file, log, hasEnv, delay, hasFileOrDir, clearLotteryInfo } = require('./lib/utils'); const metainfo = [ - ` _ _ _ _____ _ _ `, - ` | | | | | | / ____| (_) | | `, - ` | | ___ | |_| |_ ___ _ __ _ _| (___ ___ _ __ _ _ __ | |_ `, - ` | | / _ \\| __| __/ _ \\ '__| | | |\\___ \\ / __| '__| | '_ \\| __|`, - ` | |___| (_) | |_| || __/ | | |_| |____) | (__| | | | |_) | |_ `, - ` |______\\___/ \\__|\\__\\___|_| \\__, |_____/ \\___|_| |_| .__/ \\__|`, - ` __/ | | | `, - ` |___/ |_| `, - ` `, + ' _ _ _ _____ _ _ ', + ' | | | | | | / ____| (_) | | ', + ' | | ___ | |_| |_ ___ _ __ _ _| (___ ___ _ __ _ _ __ | |_ ', + ' | | / _ \\| __| __/ _ \\ \'__| | | |\\___ \\ / __| \'__| | \'_ \\| __|', + ' | |___| (_) | |_| || __/ | | |_| |____) | (__| | | | |_) | |_ ', + ' |______\\___/ \\__|\\__\\___|_| \\__, |_____/ \\___|_| |_| .__/ \\__|', + ' __/ | | | ', + ' |___/ |_| ', + ' ', ` This: v${ve} Nodejs: ${process.version} Written By shanmite`, -] +]; /**多账号存储 */ let multiple_account = []; /**循环等待时间 */ let loop_wait = 0; /**账号状态标记 1正常 -1失效 */ // eslint-disable-next-line no-unused-vars -let ck_flag = 0 +let ck_flag = 0; /** * @returns {Promise} 错误信息 @@ -40,7 +40,7 @@ async function main() { process.env.ACCOUNT_UA = acco.ACCOUNT_UA; const err_msg = await main(); if (err_msg) { - return err_msg + return err_msg; } else { if (ck_flag === 1) { await delay(acco.WAIT); @@ -53,26 +53,26 @@ async function main() { /**多账号状态还原 */ process.env.ENABLE_MULTIPLE_ACCOUNT = ENABLE_MULTIPLE_ACCOUNT; } else if (COOKIE) { - const global_var = require("./lib/data/global_var"); + const global_var = require('./lib/data/global_var'); await global_var.init(COOKIE, NUMBER); /**引入基础功能 */ - const { start, isMe, clear, account, checkCookie, login } = require("./lib/index"); + const { start, isMe, clear, account, checkCookie, login } = require('./lib/index'); log.info('main', '当前为第' + NUMBER + '个账号'); - log._cache.length = 0 + log._cache.length = 0; const mode = process.env.lottery_mode; - const help_msg = "用法: lottery [OPTIONS]\n\nOPTIONS:\n\tstart 启动抽奖\n\tcheck 中奖检查\n\tacount 查看帐号信息\n\tclear 清理动态和关注\n\tlogin 扫码登录更新CK\n\tupdate 检查更新\n\thelp 帮助信息"; + const help_msg = '用法: lottery [OPTIONS]\n\nOPTIONS:\n\tstart 启动抽奖\n\tcheck 中奖检查\n\tacount 查看帐号信息\n\tclear 清理动态和关注\n\tlogin 扫码登录更新CK\n\tupdate 检查更新\n\thelp 帮助信息'; if (await checkCookie(NUMBER)) { - const { lottery_loop_wait, check_loop_wait, clear_loop_wait, save_lottery_info_to_file } = require("./lib/data/config"); + const { lottery_loop_wait, check_loop_wait, clear_loop_wait, save_lottery_info_to_file } = require('./lib/data/config'); ck_flag = 1; switch (mode) { case 'start': log.info('抽奖', '开始运行'); loop_wait = lottery_loop_wait; if (save_lottery_info_to_file) { - await clearLotteryInfo() + await clearLotteryInfo(); } await start(NUMBER); break; @@ -92,27 +92,27 @@ async function main() { log.info('登录状态', '正常,跳过扫码'); break; case 'help': - return help_msg + return help_msg; case 'account': log.info('检查帐号信息', '开始运行'); await account(); break; case undefined: - return "未提供以下参数\n\t[OPTIONS]\n\n" + help_msg + return '未提供以下参数\n\t[OPTIONS]\n\n' + help_msg; default: - return `提供了错误的[OPTIONS] -> ${mode}\n\n` + help_msg + return `提供了错误的[OPTIONS] -> ${mode}\n\n` + help_msg; } } else { - log.error('Cookie已失效', '切换账号时不要点击退出账号而应直接删除Cookie退出') + log.error('Cookie已失效', '切换账号时不要点击退出账号而应直接删除Cookie退出'); ck_flag = -1; - if (mode === "login") { + if (mode === 'login') { log.info('登陆', '开始扫码'); await login(NUMBER); await delay(1000); } } } else { - return '请查看README文件, 在env.js指定位置填入cookie' + return '请查看README文件, 在env.js指定位置填入cookie'; } } @@ -123,7 +123,7 @@ async function main() { function initEnv() { if (hasFileOrDir(env_file)) { const - env = require("./lib/data/env"), + env = require('./lib/data/env'), multiple_account_parm = env.get_multiple_account(); if (multiple_account_parm) { @@ -139,10 +139,10 @@ function initEnv() { } else { log.init(); log.error('环境变量初始化', '未在当前目录下找到env.js文件或者在环境变量中设置所需参数'); - return true + return true; } - return false + return false; } /** @@ -151,32 +151,32 @@ function initEnv() { */ function initConfig() { if (hasFileOrDir(config_file)) { - const config = require("./lib/data/config"); + const config = require('./lib/data/config'); config.init(); log.info('配置文件初始化', '成功加载my_config.js文件'); } else { log.error('配置文件初始化', '未在当前目录下找到my_config.js文件'); - return true + return true; } - return false + return false; } (async function () { - log.rainbow(metainfo) + log.rainbow(metainfo); if (initEnv() || initConfig()) return; /**OPTIONS */ - process.env.lottery_mode = process.argv[2] + process.env.lottery_mode = process.argv[2]; - log.info('检查更新', '开始') + log.info('检查更新', '开始'); - if (process.env.lottery_mode === "update") { - await require("./lib/update").update(true) - return + if (process.env.lottery_mode === 'update') { + await require('./lib/update').update(true); + return; } else { - await require("./lib/update").update(false) + await require('./lib/update').update(false); } const err_msg = await main(); @@ -186,13 +186,13 @@ function initConfig() { await delay(5 * 1000); } else { while (loop_wait) { - log.info('程序休眠', `${loop_wait / 1000}秒后再次启动`) - await delay(loop_wait) + log.info('程序休眠', `${loop_wait / 1000}秒后再次启动`); + await delay(loop_wait); if (initEnv() || initConfig()) return; - await main() + await main(); } - log.info('结束运行', '未在my_config.js中设置休眠时间') + log.info('结束运行', '未在my_config.js中设置休眠时间'); } process.exit(0); -})() \ No newline at end of file +})(); \ No newline at end of file diff --git a/my_config.example.js b/my_config.example.js index f69550d619..d8b727acb4 100644 --- a/my_config.example.js +++ b/my_config.example.js @@ -49,13 +49,13 @@ module.exports = Object.freeze({ * @example * ["file://lottery_info_1.json"] */ - APIs: ["file://lottery_info_1.json"], + APIs: ['file://lottery_info_1.json'], /** * lottery_dyids目录下抽奖动态文件名(如dyids.txt) * 一行一个dyids(非数字字符分割即可) */ - TxT: ["dyids.txt"], + TxT: ['dyids.txt'], /** * 抽奖参与顺序组合 @@ -79,15 +79,15 @@ module.exports = Object.freeze({ * API发送数据类型 {LotteryInfo[]} * 上传抽奖信息的链接字符串 */ - set_lottery_info_url: "", + set_lottery_info_url: '', /** * 动态中的关键词(表示须同时满足以下条件) * 符合js正则表达式的字符串 */ key_words: [ - "[抽奖送揪]|福利", - "[转关评粉]|参与" + '[抽奖送揪]|福利', + '[转关评粉]|参与' ], /** @@ -313,7 +313,7 @@ module.exports = Object.freeze({ /** * 屏蔽词 */ - blockword: ["脚本", "抽奖号", "钓鱼"], + blockword: ['脚本', '抽奖号', '钓鱼'], /** * 转发并评论 @@ -349,7 +349,7 @@ module.exports = Object.freeze({ /** * 热评屏蔽词 */ - copy_blockword: ["三不原则"], + copy_blockword: ['三不原则'], /** * - 抽奖UP用户分组id(网页端点击分区后地址栏中的tagid) @@ -379,10 +379,10 @@ module.exports = Object.freeze({ * - 优先级递增 */ notice_key_words: [ - "~预约成功|预约主题", - "中奖|获得|填写|写上|提供|收货地址|支付宝账号|码|大会员", - "~你的账号在新设备或平台登录成功", - "~你预约的直播已开始" + '~预约成功|预约主题', + '中奖|获得|填写|写上|提供|收货地址|支付宝账号|码|大会员', + '~你的账号在新设备或平台登录成功', + '~你预约的直播已开始' ], /** @@ -490,4 +490,4 @@ module.exports = Object.freeze({ }, config_2: {}, config_3: {} -}) +}); diff --git a/package.json b/package.json index 981e98119e..e1d9989714 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "account": "node main.js account", "help": "node main.js help", "pkg": "bash script/build/pkg.sh", - "changelog": "bash script/build/changelog.sh" + "changelog": "bash script/build/changelog.sh", + "lint": "npx eslint lib/ test/ *.js", + "lint-fix": "npx eslint lib/ test/ *.js --fix" }, "files": [ "lib", diff --git a/test/api.test.js b/test/api.test.js index 074feb5f3e..145a02c8bf 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const bili_client = require("../lib/net/bili"); +const bili_client = require('../lib/net/bili'); const util = require('./util'); const { parseDynamicCard } = require('../lib/core/searcher'); @@ -9,47 +9,47 @@ const { parseDynamicCard } = require('../lib/core/searcher'); await util.par_run([0, 3], [ // 0 async () => { - assert.equal((await bili_client.getTopRcmd()).length, 10) + assert.equal((await bili_client.getTopRcmd()).length, 10); }, // 1 async () => { assert.equal(await bili_client.sendChat( - parseDynamicCard(await bili_client.getOneDynamicByDyid("692193323569381399")).rid_str, - "test", + parseDynamicCard(await bili_client.getOneDynamicByDyid('692193323569381399')).rid_str, + 'test', 11), 7 - ) + ); }, // 2 async () => { assert.equal(await bili_client.sendChat( - parseDynamicCard(await bili_client.getOneDynamicByDyid("11229466874154064")).rid_str, - "test", + parseDynamicCard(await bili_client.getOneDynamicByDyid('11229466874154064')).rid_str, + 'test', 1), 3 - ) + ); }, // 3 async () => { - assert.notEqual((await bili_client.searchArticlesByKeyword("专栏")).length, 0) + assert.notEqual((await bili_client.searchArticlesByKeyword('专栏')).length, 0); }, // 4 async () => { - assert.notEqual(await bili_client.sendChat("703886913053917267", "t", 17), 1) + assert.notEqual(await bili_client.sendChat('703886913053917267', 't', 17), 1); }, // 5 async () => { - assert(!await bili_client.createDynamic("1")) + assert(!await bili_client.createDynamic('1')); }, // 6 async () => { - assert.equal(await bili_client.autolike("761391835139538967"), 4) + assert.equal(await bili_client.autolike('761391835139538967'), 4); }, // 7 async () => { - assert(await bili_client.rmDynamic("835102428771647513")) + assert(await bili_client.rmDynamic('835102428771647513')); }, - ]) + ]); - console.log("api.test ... ok!"); -})() \ No newline at end of file + console.log('api.test ... ok!'); +})(); \ No newline at end of file diff --git a/test/article.test.js b/test/article.test.js index e0691e608f..bff709ea93 100644 --- a/test/article.test.js +++ b/test/article.test.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const bili_client = require("../lib/net/bili"); +const bili_client = require('../lib/net/bili'); const util = require('./util'); (async () => { @@ -8,8 +8,8 @@ const util = require('./util'); async () => { let info = await bili_client.getOneArticleByCv(22112353); let short_ids = [...new Set(info.match(/(?<=b23.tv\/)[a-zA-Z0-9]{7}/g) || [])]; - assert.equal((await Promise.all(short_ids.map(bili_client.shortDynamicIdToDyid)))[0], "767357823884460033"); + assert.equal((await Promise.all(short_ids.map(bili_client.shortDynamicIdToDyid)))[0], '767357823884460033'); }, - ]) - console.log("article.test ... ok!"); -})() \ No newline at end of file + ]); + console.log('article.test ... ok!'); +})(); \ No newline at end of file diff --git a/test/dynamic_card.test.js b/test/dynamic_card.test.js index aec1dd263d..7d37c9beac 100644 --- a/test/dynamic_card.test.js +++ b/test/dynamic_card.test.js @@ -1,33 +1,33 @@ const assert = require('assert'); -const bili_client = require("../lib/net/bili"); -const searcher = require("../lib/core/searcher"); +const bili_client = require('../lib/net/bili'); +const searcher = require('../lib/core/searcher'); const util = require('./util'); (async () => { await util.par_run([0, 1, 2, 3, 4, 5, 6, 7, 8], [ // 0 async () => { - let info = await bili_client.getOneDynamicByDyid("728424890210713624"); + let info = await bili_client.getOneDynamicByDyid('728424890210713624'); assert(searcher.parseDynamicCard(info).is_charge_lottery); }, // 1 async () => { - let info = await bili_client.getOneDynamicByDyid("768874900850999300"); + let info = await bili_client.getOneDynamicByDyid('768874900850999300'); assert(searcher.parseDynamicCard(info).origin_is_charge_lottery); }, // 2 async () => { - let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("746824225190314008")); - let chats = await bili_client.getChat(card.rid_str, card.chat_type) - assert(chats.length > 0 && typeof chats[0][0] == "string") + let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid('746824225190314008')); + let chats = await bili_client.getChat(card.rid_str, card.chat_type); + assert(chats.length > 0 && typeof chats[0][0] == 'string'); }, // 3 async () => { - let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("900172162530279445")); - assert.equal(card.chat_type, 11) - card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("926978638295859236")); - assert.equal(card.chat_type, 17) - assert.equal(card.origin_chat_type, 11) + let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid('900172162530279445')); + assert.equal(card.chat_type, 11); + card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid('926978638295859236')); + assert.equal(card.chat_type, 17); + assert.equal(card.origin_chat_type, 11); }, // 4 async () => { @@ -37,32 +37,32 @@ const util = require('./util'); }, // 5 async () => { - let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("762591475338838053")); - let chats = await bili_client.getChat(card.rid_str, card.chat_type) - assert.equal(chats.length, 19) - card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid("762502724122050647")); - chats = await bili_client.getChat(card.rid_str, card.chat_type) - assert.equal(chats.filter(it => it[0] === '六的月').length, 0) + let card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid('762591475338838053')); + let chats = await bili_client.getChat(card.rid_str, card.chat_type); + assert.equal(chats.length, 19); + card = searcher.parseDynamicCard(await bili_client.getOneDynamicByDyid('762502724122050647')); + chats = await bili_client.getChat(card.rid_str, card.chat_type); + assert.equal(chats.filter(it => it[0] === '六的月').length, 0); }, // 6 async () => { - const dy = await bili_client.getOneDynamicByDyid("774973685666676768"); - const card = searcher.parseDynamicCard(dy) - assert.notEqual(card.description + "", undefined + ""); + const dy = await bili_client.getOneDynamicByDyid('774973685666676768'); + const card = searcher.parseDynamicCard(dy); + assert.notEqual(card.description + '', undefined + ''); }, // 7 async () => { - const dy = await bili_client.getOneDynamicByDyid("924676093465591832"); - const card = searcher.parseDynamicCard(dy) - assert.equal(card.reserve_id, "3715576"); + const dy = await bili_client.getOneDynamicByDyid('924676093465591832'); + const card = searcher.parseDynamicCard(dy); + assert.equal(card.reserve_id, '3715576'); }, // 8 async () => { - const dy = await bili_client.getOneDynamicByDyid("925061227481137187"); - const card = searcher.parseDynamicCard(dy) - assert.equal(card.origin_reserve_id, "3715576"); + const dy = await bili_client.getOneDynamicByDyid('925061227481137187'); + const card = searcher.parseDynamicCard(dy); + assert.equal(card.origin_reserve_id, '3715576'); }, - ]) + ]); - console.log("dynamic_card.test ... ok!"); -})() \ No newline at end of file + console.log('dynamic_card.test ... ok!'); +})(); \ No newline at end of file diff --git a/test/index.js b/test/index.js index 29d3210464..e9ce9be1c3 100644 --- a/test/index.js +++ b/test/index.js @@ -1,12 +1,12 @@ -const env = require("../lib/data/env"); -const global_var = require("../lib/data/global_var"); +const env = require('../lib/data/env'); +const global_var = require('../lib/data/global_var'); const { log } = require('../lib/utils'); const fs = require('fs'); -log._level = 4 -env.init() -global_var.init(process.env["COOKIE"], 1) +log._level = 4; +env.init(); +global_var.init(process.env['COOKIE'], 1); fs.readdirSync(module.path) - .filter(file => file.endsWith(".test.js")) - .forEach(file => require(`${module.path}/${file}`)) \ No newline at end of file + .filter(file => file.endsWith('.test.js')) + .forEach(file => require(`${module.path}/${file}`)); \ No newline at end of file diff --git a/test/ocr.test.js b/test/ocr.test.js index 91e460684a..d2fcde2387 100644 --- a/test/ocr.test.js +++ b/test/ocr.test.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const bili_client = require("../lib/net/bili"); +const bili_client = require('../lib/net/bili'); const util = require('./util'); const { parseDynamicCard } = require('../lib/core/searcher'); @@ -9,7 +9,7 @@ const { parseDynamicCard } = require('../lib/core/searcher'); async () => { assert.notEqual(await bili_client.getMyinfo(), null); - const rid = parseDynamicCard(await bili_client.getOneDynamicByDyid("551416252543796684")).rid_str; + const rid = parseDynamicCard(await bili_client.getOneDynamicByDyid('551416252543796684')).rid_str; for (let index = 0; index < 100; index++) { console.log(index); @@ -17,7 +17,7 @@ const { parseDynamicCard } = require('../lib/core/searcher'); rid, Date.now().toString(), 17, - ) + ); } },]); -})() +})(); diff --git a/test/util.js b/test/util.js index 9b10195ffe..861c362ada 100644 --- a/test/util.js +++ b/test/util.js @@ -5,9 +5,9 @@ function par_run(nums, fns) { return Promise.all( nums.map(num => fns[num]()) - ) + ); } module.exports = { par_run -} \ No newline at end of file +}; \ No newline at end of file From 74337ca493a93ef9a70bad7b1009f194a3ce205f Mon Sep 17 00:00:00 2001 From: shanmite Date: Tue, 20 Aug 2024 08:45:35 +0800 Subject: [PATCH 37/74] =?UTF-8?q?fix:=20=E8=B4=A6=E5=8F=B7=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E5=8A=A8=E6=80=81=E9=80=94=E4=B8=AD=E8=A2=AB=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E5=BC=BA=E5=88=B6=E7=99=BB=E5=87=BA=EF=BC=8C=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=9B=B4=E6=8E=A5=E7=BB=88=E6=AD=A2=20(#392)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #392 --- lib/core/searcher.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index adcad27235..a3242e7822 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -321,7 +321,7 @@ function oldParseDynamicCard(dynamic_detail_card) { * @returns {{modifyDynamicResArray: UsefulDynamicInfo[], nextinfo: {has_more: number, next_offset: string}} | UsefulDynamicInfo |null} */ function modifyDynamicRes(res) { - const + let { data, code } = utils.strToJson(res), { cards, has_more, offset } = data || {}; @@ -332,6 +332,7 @@ function modifyDynamicRes(res) { if (cards == null || !cards || !cards.length) { log.warn('处理动态数据', '未找到任何动态信息'); + cards = []; } if (typeof has_more === 'undefined' From 9b0f9bf108cecd93f05d30403499c25429b88f16 Mon Sep 17 00:00:00 2001 From: shanmite Date: Tue, 20 Aug 2024 09:12:24 +0800 Subject: [PATCH 38/74] =?UTF-8?q?fix:=20=E4=BB=85=E5=B1=8F=E8=94=BD?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=9B=9E=E5=A4=8D=20(#401)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #401 --- lib/net/bili.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net/bili.js b/lib/net/bili.js index 7273a9f228..619d3211a0 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -319,7 +319,7 @@ const bili_client = { const msgs = res.data.messages; if (msgs instanceof Array) { log.info('私信细节', `${talker_id}有${size}条未读私信`); - return msgs.filter(it => ![5, 8, 9, 10, 11].includes(it.msg_source)).map(it => it.content).join('\n'); + return msgs.filter(it => ![8].includes(it.msg_source)).map(it => it.content).join('\n'); } else { log.warn('私信细节', `${talker_id}无私信`); } From 47e318dc3d14dd04ac8bcbdb4a23e4ab0b6e6ced Mon Sep 17 00:00:00 2001 From: shanmite Date: Wed, 21 Aug 2024 07:56:34 +0800 Subject: [PATCH 39/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- script/build/changelog.sh | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee07320aa0..91a8cf44e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## 主要变化(2.9.1) +* 9b0f9bf fix: 仅屏蔽自动回复 (#401) +* 74337ca fix: 账号转发动态途中被系统强制登出,任务直接终止 (#392) +* 6c75d57 lint: eslint +* e723136 feat: 可自定义验证码识别API + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.0) * 1e7d8b2 feat: 动态详情新老api共存 * fc41750 fix: 源rid_str获取 diff --git a/package.json b/package.json index e1d9989714..c865aa660d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.0", + "version": "2.9.1", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { diff --git a/script/build/changelog.sh b/script/build/changelog.sh index 88045f5428..b2a6ec6905 100644 --- a/script/build/changelog.sh +++ b/script/build/changelog.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # version: -level=minor +level=patch npm version $level \ --no-commit-hooks \ From d3475a50329df5cc4bcae90e2065fbadd00a0da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B7=B4=E6=8B=89=E5=B7=B4=E6=8B=89=E5=98=BF?= <83610194+superHao2000@users.noreply.github.com> Date: Fri, 13 Sep 2024 20:51:43 +0800 Subject: [PATCH 40/74] =?UTF-8?q?feat(notify.js):=20QYWX=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E5=8F=98=E4=B8=BA=E5=9B=BE=E6=96=87=E6=B6=88=E6=81=AF=20(#416)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/helper/notify.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/helper/notify.js b/lib/helper/notify.js index 3ebe504f40..d965b1d91e 100644 --- a/lib/helper/notify.js +++ b/lib/helper/notify.js @@ -619,6 +619,7 @@ function ddBotNotify(text, desp) { function qywxAmNotify(text, desp) { return new Promise(resolve => { + desp=desp.replace(/\n/g, '
'); if (QYWX_AM) { const QYWX_AM_AY = QYWX_AM.split(','); send({ @@ -646,9 +647,15 @@ function qywxAmNotify(text, desp) { touser: `${QYWX_AM_AY[2]}`, agentid: `${QYWX_AM_AY[3]}`, safe: '0', - msgtype: 'text', - text: { - content: `${text}\n\n${desp}`, + msgtype: 'mpnews', + mpnews : { + articles:[ + { + title: `${text}`, + thumb_media_id: `${QYWX_AM_AY[4]}`, + content: `${desp}`, + } + ] }, }, config: { From b1de122c754ec937e0aa67a9de2d85e8784c85a8 Mon Sep 17 00:00:00 2001 From: shanmite Date: Thu, 19 Sep 2024 11:10:42 +0800 Subject: [PATCH 41/74] =?UTF-8?q?fix:=20=E9=AA=8C=E8=AF=81=E7=A0=81?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E5=A4=B1=E8=B4=A5=E6=97=A0=E9=99=90=E9=87=8D?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/bili.js | 3 +++ lib/utils.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/net/bili.js b/lib/net/bili.js index 619d3211a0..efdf9cfdbd 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -1159,6 +1159,9 @@ const bili_client = { } else { need_captcha = false; } + } else { + log.error('验证码识别', '失败'); + break; } } else { url = await bili_client.sendChat( diff --git a/lib/utils.js b/lib/utils.js index 5f92b9b944..9baad52128 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -296,7 +296,7 @@ const utils = { resolve(res.body); }, failure: () => { - resolve(); + resolve(null); } }); }); From 66fa06f1f0dbc7b355fedf65b1852672c8e00d64 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 8 Nov 2024 10:28:44 +0800 Subject: [PATCH 42/74] =?UTF-8?q?fix:=20=E6=BA=90=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E7=A6=81=E6=AD=A2=E8=BD=AC=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/monitor.js | 2 ++ lib/net/bili.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index ad44b2a4c5..235e02ec51 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -207,6 +207,7 @@ class Monitor extends Searcher { case 5002: case 5003: case 5004: + case 5005: status = 0; break; case 2004: @@ -572,6 +573,7 @@ class Monitor extends Searcher { * - 转发 该动态不能转发分享 5002 * - 转发 请求数据发生错误,请刷新或稍后重试 5003 * - 转发 操作太频繁了,请稍后重试 5004 + * - 转发 源动态禁止转发 5005 */ async go(option) { log.debug('正在转发的动态信息', option); diff --git a/lib/net/bili.js b/lib/net/bili.js index efdf9cfdbd..a0be37808f 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -841,6 +841,7 @@ const bili_client = { * - 该动态不能转发分享 2 * - 请求数据发生错误,请刷新或稍后重试 3 * - 操作太频繁了,请稍后重试 4 + * - 源动态禁止转发 5 */ async autoRelay(uid, dyid, msg = '转发动态', ctrl = '[]') { const len = msg.length; @@ -875,6 +876,9 @@ const bili_client = { case 1101008: log.warn('转发动态', '操作太频繁了,请稍后重试'); return 4; + case 4126117: + log.warn('转发动态', '源动态禁止转发'); + return 5; default: log.error('转发动态', `未知错误\n${responseText}`); return 1; From 4134190927746dc98dba53374152062fa20a8972 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 8 Nov 2024 10:37:35 +0800 Subject: [PATCH 43/74] =?UTF-8?q?fix:=20=E5=88=86=E5=8C=BA=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E5=A4=B1=E8=B4=A5=E7=BB=A7=E7=BB=AD=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=20(#423)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #423 --- lib/core/monitor.js | 5 +---- lib/net/bili.js | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 235e02ec51..874a91ea11 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -65,9 +65,6 @@ class Monitor extends Searcher { case 2001: event_bus.emit('Turn_off_the_Monitor', '关注出错'); break; - case 3001: - event_bus.emit('Turn_off_the_Monitor', '分区移动出错 可于设置处关闭移动分区'); - break; case 2004: case 4005: log.warn(`账号异常${status}`, `UID(${global_var.get('myUID')})异常号只会对部分UP出现异常`); @@ -200,6 +197,7 @@ class Monitor extends Searcher { case 1011: case 2002: case 2003: + case 3001: case 4001: case 4002: case 4003: @@ -223,7 +221,6 @@ class Monitor extends Searcher { case 1010: case 1004: case 2001: - case 3001: case 5001: is_shutdown = true; break; diff --git a/lib/net/bili.js b/lib/net/bili.js index a0be37808f..a518bf518d 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -751,7 +751,7 @@ const bili_client = { log.info('移动分区', 'up主分区移动成功'); return 0; } else { - log.error('移动分区', `up主分区移动失败\n${responseText}`); + log.error('移动分区', `up主分区移动失败分区 可于设置处关闭移动分区\n${responseText}`); return 1; } }, From 890c86c3afded7dffa02b69b56ed967d7b6031aa Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 8 Nov 2024 10:41:03 +0800 Subject: [PATCH 44/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91a8cf44e0..20543e1ce5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## 主要变化(2.9.2) +* 4134190 fix: 分区移动失败继续运行 (#423) +* 66fa06f fix: 源动态禁止转发 +* b1de122 fix: 验证码识别失败无限重试 +* d3475a5 feat(notify.js): QYWX推送变为图文消息 (#416) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.1) * 9b0f9bf fix: 仅屏蔽自动回复 (#401) * 74337ca fix: 账号转发动态途中被系统强制登出,任务直接终止 (#392) diff --git a/package.json b/package.json index c865aa660d..84c6f3eacb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.1", + "version": "2.9.2", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 1d4e8eaacaff9c0acc2127a4ffbf0b8042c88609 Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 9 Nov 2024 13:50:13 +0800 Subject: [PATCH 45/74] =?UTF-8?q?fix:=20=E4=B8=93=E6=A0=8F=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E4=B8=BA=E7=A9=BA=20(#425)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #425 --- lib/net/bili.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/net/bili.js b/lib/net/bili.js index a518bf518d..47ee6fd1d8 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -568,7 +568,10 @@ const bili_client = { */ getOneArticleByCv(cv) { return get({ - url: API.READ_CV.replace('{{cv}}', cv) + url: API.READ_CV.replace('{{cv}}', cv), + config: { + redirect: true + } }); }, /** From 6b1c2310cabf325168180fda9fe908ea873ad346 Mon Sep 17 00:00:00 2001 From: shanmite Date: Sat, 9 Nov 2024 13:51:13 +0800 Subject: [PATCH 46/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20543e1ce5..0209f73766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 主要变化(2.9.3) +* 1d4e8ea fix: 专栏获取为空 (#425) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.2) * 4134190 fix: 分区移动失败继续运行 (#423) * 66fa06f fix: 源动态禁止转发 diff --git a/package.json b/package.json index 84c6f3eacb..21127a8ae2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.2", + "version": "2.9.3", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 2f5990f2773b6ff59e49d0b74aded6f09368d6f7 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 18 Nov 2024 13:55:05 +0800 Subject: [PATCH 47/74] =?UTF-8?q?fix:=20=E5=8A=A8=E6=80=81ID=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E9=95=BF=E5=BA=A6=E8=B6=85=E8=BF=8718?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 95 ++++++++++++++++++--------------------- lib/helper/d_storage.js | 52 ++++++++++++--------- lib/net/bili.js | 2 +- lib/utils.js | 4 +- test/api.test.js | 2 +- test/dyidSearch.test.js | 14 ++++++ test/dynamic_card.test.js | 2 +- 7 files changed, 92 insertions(+), 79 deletions(-) create mode 100644 test/dyidSearch.test.js diff --git a/lib/core/searcher.js b/lib/core/searcher.js index a3242e7822..e64b98808b 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -582,7 +582,7 @@ class Searcher { } const content = (await bili.getOneArticleByCv(id) || '').split('推荐文章')[0], - dyids = content.match(/[0-9]{18}/g) || [], + dyids = content.match(/[0-9]{18,}/g) || [], short_ids = content.match(/(?<=b23.tv\/)[a-zA-Z0-9]{7}/g) || [], short_id_set = [...new Set(short_ids)], short_ids_to_dyids = await Promise.all(short_id_set.map(bili.shortDynamicIdToDyid)), @@ -599,38 +599,34 @@ class Searcher { /**遍历某专栏中的dyids */ for (const dyid of dyid_set) { - if (typeof dyid === 'string' - && dyid.length === utils.dyid_length) { + log.info('获取动态', `查看专栏中所提及动态(${dyid}) (${length--})`); + const card = await bili.getOneDynamicByDyid(dyid); - log.info('获取动态', `查看专栏中所提及动态(${dyid}) (${length--})`); - const card = await bili.getOneDynamicByDyid(dyid); + if (card) { + await utils.delay(get_dynamic_detail_wait); - if (card) { - await utils.delay(get_dynamic_detail_wait); - - const parsed_card = parseDynamicCard(card) - , { is_liked } = parsed_card; - - if ( - ((!check_if_duplicated || check_if_duplicated >= 2) - && is_liked) - || ((check_if_duplicated >= 1) - && await d_storage.searchDyid(dyid)) - ) { - log.info('获取动态', `动态(${dyid})已转发过`); - _weight += 1; - } + const parsed_card = parseDynamicCard(card) + , { is_liked } = parsed_card; - if (_weight >= weight && !not_check_article) { - log.warn('获取动态', '1/2动态曾经转过,该专栏或已查看,故中止'); - _dyinfos = []; - break; - } + if ( + ((!check_if_duplicated || check_if_duplicated >= 2) + && is_liked) + || ((check_if_duplicated >= 1) + && await d_storage.searchDyid(dyid)) + ) { + log.info('获取动态', `动态(${dyid})已转发过`); + _weight += 1; + } - _dyinfos.push(parsed_card); + if (_weight >= weight && !not_check_article) { + log.warn('获取动态', '1/2动态曾经转过,该专栏或已查看,故中止'); + _dyinfos = []; + break; } + + _dyinfos.push(parsed_card); } else { - log.warn('获取动态', `动态(${dyid})无效 (${length--})`); + log.warn('获取动态', `动态细节获取失败(${dyid})`); } } dyinfos.push(..._dyinfos); @@ -751,33 +747,30 @@ class Searcher { dyinfos = []; for (const dyid of dyids) { - if (typeof dyid === 'string' - && dyid.length === utils.dyid_length) { - - log.info('获取动态', `查看Txt中所提及动态(${dyid}) (${length--})`); - const card = await bili.getOneDynamicByDyid(dyid); - - if (card) { - await utils.delay(get_dynamic_detail_wait); - - const parsed_card = parseDynamicCard(card) - , { is_liked } = parsed_card; - - if ( - ((!check_if_duplicated || check_if_duplicated >= 2) - && is_liked) - || ((check_if_duplicated >= 1) - && await d_storage.searchDyid(dyid)) - ) { - log.info('获取动态', `动态(${dyid})已转发过`); - continue; - } - - dyinfos.push(parsed_card); + log.info('获取动态', `查看Txt中所提及动态(${dyid}) (${length--})`); + const card = await bili.getOneDynamicByDyid(dyid); + + if (card) { + await utils.delay(get_dynamic_detail_wait); + + const parsed_card = parseDynamicCard(card) + , { is_liked } = parsed_card; + + if ( + ((!check_if_duplicated || check_if_duplicated >= 2) + && is_liked) + || ((check_if_duplicated >= 1) + && await d_storage.searchDyid(dyid)) + ) { + log.info('获取动态', `动态(${dyid})已转发过`); + continue; } + + dyinfos.push(parsed_card); } else { - log.warn('获取动态', `动态(${dyid})无效 (${length--})`); + log.warn('获取动态', `动态细节获取失败(${dyid})`); } + } const fomatdata = dyinfos.map(o => { return { diff --git a/lib/helper/d_storage.js b/lib/helper/d_storage.js index 46c54faf17..3f308ed3b6 100644 --- a/lib/helper/d_storage.js +++ b/lib/helper/d_storage.js @@ -1,4 +1,4 @@ -const { log, readDyidFile, writeDyidFile, dyid_length } = require('../utils'); +const { log, readDyidFile, writeDyidFile } = require('../utils'); const d_storage = { /** @@ -6,24 +6,35 @@ const d_storage = { * @param {string} dyid * @returns {Promise} */ - searchDyid: (dyid) => { - return new Promise((resolve) => { - const Rdyid = new RegExp(dyid); - const rs = readDyidFile(Number(process.env.NUMBER)); - let status = false; - rs.on('data', chunk => { - if (Rdyid.test(chunk)) { - status = true; - } - }); - rs.on('end', () => { - resolve(status); - }); - rs.on('error', err => { - log.error('搜索dyid', err); - resolve(status); - }); - }); + searchDyid: async (dyid) => { + let buffer = ''; + let found = false; + + const stream = readDyidFile(Number(process.env.NUMBER)); + + for await (const chunk of stream) { + buffer += chunk; + + while ((buffer.indexOf(dyid)) !== -1) { + found = true; + stream.destroy(); + return found; + } + + const lastCommaIdx = buffer.lastIndexOf(','); + if (lastCommaIdx !== -1) { + buffer = buffer.slice(lastCommaIdx); + } + } + + if (!found && buffer.length > 0) { + if (buffer.includes(dyid)) { + found = true; + } + } + + stream.destroy(); + return found; }, /** * 更新dyid @@ -31,9 +42,6 @@ const d_storage = { */ updateDyid: (dyid) => { log.info('更新dyid', `写入${dyid}`); - if (dyid.length !== dyid_length) { - log.error('更新dyid', `dyid(${dyid})长度不为18 若出现此问题请即时通知开发者`); - } return new Promise((resolve) => { const ws = writeDyidFile(Number(process.env.NUMBER)); ws.write(dyid + ',', () => { diff --git a/lib/net/bili.js b/lib/net/bili.js index 47ee6fd1d8..0cc02a53bc 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -407,7 +407,7 @@ const bili_client = { redirect: false, } }).then(a => { - const dyid = (a.match(/[0-9]{18}/) || [])[0]; + const dyid = (a.match(/[0-9]{18,}/) || [])[0]; log.info('短连接转换', `${short_id} -> ${dyid}`); return dyid; }); diff --git a/lib/utils.js b/lib/utils.js index 9baad52128..c82f856ba8 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -19,8 +19,6 @@ const utils = { lottery_info_dir: path.join(process.cwd(), 'lottery_info'), /**本地抽奖信息存放目录 */ lottery_dyids: path.join(process.cwd(), 'lottery_dyids'), - /**dyid长度 */ - dyid_length: 18, /** * 将版本号转为数字 * @example @@ -402,7 +400,7 @@ const utils = { */ readDyidFile(num) { const fpath = num < 2 ? path.join(utils.dyids_dir, 'dyid.txt') : path.join(utils.dyids_dir, `dyid${num}.txt`); - return fs.createReadStream(fpath, { encoding: 'utf8', highWaterMark: (utils.dyid_length + 1) * 1000 }); + return fs.createReadStream(fpath, { encoding: 'utf8' }); }, /** * 追加dyid diff --git a/test/api.test.js b/test/api.test.js index 145a02c8bf..59f745e698 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -6,7 +6,7 @@ const { parseDynamicCard } = require('../lib/core/searcher'); (async () => { assert.notEqual(await bili_client.getMyinfo(), null); - await util.par_run([0, 3], [ + await util.par_run([], [ // 0 async () => { assert.equal((await bili_client.getTopRcmd()).length, 10); diff --git a/test/dyidSearch.test.js b/test/dyidSearch.test.js new file mode 100644 index 0000000000..f493c0ac03 --- /dev/null +++ b/test/dyidSearch.test.js @@ -0,0 +1,14 @@ +const assert = require('assert'); +const util = require('./util'); +const d_storage = require('../lib/helper/d_storage'); + +(async () => { + await util.par_run([0], [ + // 0 + async () => { + assert(await d_storage.searchDyid('1234567901234568')); + assert(!await d_storage.searchDyid('1234567901234569')); + }, + ]); + console.log('dyidSearch.test ... ok!'); +})(); \ No newline at end of file diff --git a/test/dynamic_card.test.js b/test/dynamic_card.test.js index 7d37c9beac..010599faf7 100644 --- a/test/dynamic_card.test.js +++ b/test/dynamic_card.test.js @@ -4,7 +4,7 @@ const searcher = require('../lib/core/searcher'); const util = require('./util'); (async () => { - await util.par_run([0, 1, 2, 3, 4, 5, 6, 7, 8], [ + await util.par_run([], [ // 0 async () => { let info = await bili_client.getOneDynamicByDyid('728424890210713624'); From a4215f1881f6f8c09bea46845961f364fc099139 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 18 Nov 2024 13:55:38 +0800 Subject: [PATCH 48/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0209f73766..685e342956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 主要变化(2.9.4) +* 2f5990f fix: 动态ID字符串长度超过18 + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.3) * 1d4e8ea fix: 专栏获取为空 (#425) diff --git a/package.json b/package.json index 21127a8ae2..354180b943 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.3", + "version": "2.9.4", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 717d8cf2813e80ff353cad7b4ec4c5306157e83a Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 2 Dec 2024 17:11:50 +0800 Subject: [PATCH 49/74] =?UTF-8?q?fix:=20=E6=8D=A2=E6=BA=90gitlab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/run_use_docker.md | 2 +- script/docker/init.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/run_use_docker.md b/doc/run_use_docker.md index 79f7441b21..2bb79c6dd1 100644 --- a/doc/run_use_docker.md +++ b/doc/run_use_docker.md @@ -1,7 +1,7 @@ 1.初始化 ```bash -curl -fsSL https://ghproxy.com/https://raw.githubusercontent.com/shanmiteko/LotteryAutoScript/main/script/docker/init.sh | sudo bash +curl -fsSL https://gitlab.com/shanmiteko/LotteryAutoScript/-/raw/main/script/docker/init.sh | sudo bash ``` 进入`lottery`文件夹 diff --git a/script/docker/init.sh b/script/docker/init.sh index a6f1e7848e..d367fe194a 100755 --- a/script/docker/init.sh +++ b/script/docker/init.sh @@ -37,7 +37,7 @@ CONFIG_FILE=my_config.js # docker仓库 DOCKER_REPO=shanmite/lottery_auto_docker # cdn -CDN=https://cdn.staticaly.com/gh/shanmiteko/LotteryAutoScript/main +CDN=https://gitlab.com/shanmiteko/LotteryAutoScript/-/raw/main # env.example.js文件 ENV_EXAMPLE="$CDN/env.example.js" # my_config.example.js文件 From 1832f6d52bee97ab56f5ad81f2434ec6835c0aa4 Mon Sep 17 00:00:00 2001 From: amadeus5201 <57700419+amadeus5201@users.noreply.github.com> Date: Thu, 16 Jan 2025 08:04:30 +0800 Subject: [PATCH 50/74] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E7=9A=84=E4=BB=A3=E7=90=86=20(#433)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat=>增加多账号的代理 * feat=>增加多账号的代理 * fix=>变量声明 --- env.example.js | 6 +++++- lib/utils.js | 35 ++++++++++++++++++++++++++++------- main.js | 37 +++++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/env.example.js b/env.example.js index f237ed1e75..9feef3c69d 100644 --- a/env.example.js +++ b/env.example.js @@ -64,7 +64,11 @@ module.exports = Object.freeze({ NUMBER: 1, CLEAR: true, WAIT: 60 * 1000, - ACCOUNT_UA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36' + ACCOUNT_UA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', + PROXY_HOST:'',//代理ip + PROXY_PORT:'',//代理ip端口 + PROXY_USER:'',//代理ip账号 + PROXY_PASS:'',//代理ip密码 } ], diff --git a/lib/utils.js b/lib/utils.js index c82f856ba8..66566748fd 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -98,6 +98,7 @@ const utils = { return _c(restNum - 1, argsList.concat(x)); }; } + return _c(func.length, []); }, /** @@ -121,7 +122,9 @@ const utils = { let c = { i: 0, next: () => c.i++, - clear: () => { c.i = 0; }, + clear: () => { + c.i = 0; + }, value: () => c.i }; return c; @@ -130,7 +133,7 @@ const utils = { * 无限序列 * `[0..]` */ - *infiniteNumber() { + * infiniteNumber() { for (let index = 0; ; index++) { yield index; } @@ -178,7 +181,7 @@ const utils = { /** * 是否有指定环境变量 * @param {string} env_name - * @returns + * @returns */ hasEnv(env_name) { return process.env[env_name] ? true : false; @@ -278,7 +281,7 @@ const utils = { }, /** * 验证码识别 - * @param {string} url + * @param {string} url * @returns {Promise} */ ocr(url) { @@ -340,7 +343,7 @@ const utils = { /** * 是否存在文件或目录 * @param {string} path - * @returns + * @returns */ hasFileOrDir(path) { try { @@ -414,7 +417,7 @@ const utils = { /** * 追加lotteryinfo * @param {string} from - * @param {import("./core/searcher").LotteryInfo[]} lottery_info + * @param {import('./core/searcher').LotteryInfo[]} lottery_info * @return {Promise} */ async appendLotteryInfoFile(from, lottery_info) { @@ -435,7 +438,7 @@ const utils = { /** * 读取lottery_info * @param {string} filename - * @return {Promise} + * @return {Promise} */ readLotteryInfoFile(filename) { return new Promise((resolve) => { @@ -471,6 +474,24 @@ const utils = { } }); }); + }, + getIpInfo() { + return new Promise((resolve) => { + send({ + url: 'https://myip.qq.com/', + method: 'GET', + success: res => resolve(res.body), + failure: err => resolve(err) + }); + }); + }, + printIpInfo(beforeProxy) { + const printMessage = beforeProxy ? '当前IP----->' : '代理后IP=======>'; + utils.getIpInfo().then(res => { + console.log(printMessage + res); + }).catch((err) => { + console.error('获取' + printMessage + '地址失败', err); + }); } }; diff --git a/main.js b/main.js index 86556234c5..5fd6ffba96 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,15 @@ -const { version: ve, env_file, config_file, log, hasEnv, delay, hasFileOrDir, clearLotteryInfo } = require('./lib/utils'); - +const { + version: ve, + env_file, + config_file, + log, + hasEnv, + delay, + hasFileOrDir, + clearLotteryInfo, printIpInfo +} = require('./lib/utils'); +const { HttpsProxyAgent } = require('https-proxy-agent'); +const request = require('https'); const metainfo = [ ' _ _ _ _____ _ _ ', ' | | | | | | / ____| (_) | | ', @@ -31,6 +41,7 @@ async function main() { : JSON.parse(MULTIPLE_ACCOUNT_PARM); process.env.ENABLE_MULTIPLE_ACCOUNT = ''; + let localhost = request.globalAgent; for (const acco of muti_acco) { process.env.COOKIE = acco.COOKIE; @@ -38,6 +49,19 @@ async function main() { process.env.CLEAR = acco.CLEAR; process.env.NOTE = acco.NOTE; process.env.ACCOUNT_UA = acco.ACCOUNT_UA; + if (acco.PROXY_HOST) { + printIpInfo(true); + //http://ip:port + //http://user:pwd@ip:port' + const proxyUrl = acco.PROXY_USER + ? 'http://' + acco.PROXY_USER + ':' + acco.PROXY_PASS + '@' + acco.PROXY_HOST + ':' + acco.PROXY_PORT + : 'http://' + acco.PROXY_HOST + ':' + acco.PROXY_PORT; + request.globalAgent = new HttpsProxyAgent(proxyUrl); + printIpInfo(false); + }else { + //未设置还原 + request.globalAgent = localhost; + } const err_msg = await main(); if (err_msg) { return err_msg; @@ -48,8 +72,8 @@ async function main() { await delay(3 * 1000); } } + request.globalAgent = localhost; } - /**多账号状态还原 */ process.env.ENABLE_MULTIPLE_ACCOUNT = ENABLE_MULTIPLE_ACCOUNT; } else if (COOKIE) { @@ -65,7 +89,12 @@ async function main() { const mode = process.env.lottery_mode; const help_msg = '用法: lottery [OPTIONS]\n\nOPTIONS:\n\tstart 启动抽奖\n\tcheck 中奖检查\n\tacount 查看帐号信息\n\tclear 清理动态和关注\n\tlogin 扫码登录更新CK\n\tupdate 检查更新\n\thelp 帮助信息'; if (await checkCookie(NUMBER)) { - const { lottery_loop_wait, check_loop_wait, clear_loop_wait, save_lottery_info_to_file } = require('./lib/data/config'); + const { + lottery_loop_wait, + check_loop_wait, + clear_loop_wait, + save_lottery_info_to_file + } = require('./lib/data/config'); ck_flag = 1; switch (mode) { case 'start': From f5f63bcc91bc555a8e2716b9afcb8617c43c7dec Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Tue, 6 May 2025 14:58:31 +0800 Subject: [PATCH 51/74] =?UTF-8?q?fix:=20=E5=AE=98=E6=96=B9=E6=8A=BD?= =?UTF-8?q?=E5=A5=96=E5=88=A4=E6=96=AD=E6=9C=AA=E8=8E=B7=E5=8F=96=E5=88=B0?= =?UTF-8?q?=E5=86=85=E5=AE=B9=20(#445)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #445 增加ditem?.modules?.module_dynamic?.major?.opus?.summary?.rich_text_nodes 判断 --- lib/core/searcher.js | 75 ++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index e64b98808b..5318c5e5e6 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -103,22 +103,41 @@ function parseDynamicCard(data) { /* 转发描述 */ obj.description = ''; let _total_len = 0; - ditem?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { - if (node.type === 'RICH_TEXT_NODE_TYPE_AT') { - obj.ctrl.push({ - data: node.rid, - location: _total_len, - length: node.text.length, - type: 1 - }); - } - /* 是否有官方抽奖 */ - if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { - obj.hasOfficialLottery = true; - } - obj.description += node.orig_text; - _total_len += node.text.length; - }); + if (Array.isArray(ditem?.modules?.module_dynamic?.desc?.rich_text_nodes)) { + ditem?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { + if (node.type === 'RICH_TEXT_NODE_TYPE_AT') { + obj.ctrl.push({ + data: node.rid, + location: _total_len, + length: node.text.length, + type: 1 + }); + } + /* 是否有官方抽奖 */ + if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { + obj.hasOfficialLottery = true; + } + obj.description += node.orig_text; + _total_len += node.text.length; + }); + } else { + ditem?.modules?.module_dynamic?.major?.opus?.summary?.rich_text_nodes.forEach(node => { + if (node.type === 'RICH_TEXT_NODE_TYPE_AT') { + obj.ctrl.push({ + data: node.rid, + location: _total_len, + length: node.text.length, + type: 1 + }); + } + /* 是否有官方抽奖 */ + if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { + obj.hasOfficialLottery = true; + } + obj.description += node.orig_text; + _total_len += node.text.length; + }); + } /* 预约抽奖信息 */ obj.reserve_id = ditem?.modules?.module_dynamic?.additional?.reserve?.rid || 0; obj.reserve_lottery_text = ditem?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失'; @@ -166,13 +185,23 @@ function parseDynamicCard(data) { obj.origin_hasOfficialLottery = false; /* 转发描述 */ obj.origin_description = ''; - ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { - /* 是否有官方抽奖 */ - if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { - obj.origin_hasOfficialLottery = true; - } - obj.origin_description += node.orig_text; - }); + if (Array.isArray(ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes)) { + ditem?.orig?.modules?.module_dynamic?.desc?.rich_text_nodes.forEach(node => { + /* 是否有官方抽奖 */ + if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { + obj.origin_hasOfficialLottery = true; + } + obj.origin_description += node.orig_text; + }); + } else { + ditem?.orig.modules?.module_dynamic?.major?.opus?.summary?.rich_text_nodes.forEach(node => { + /* 是否有官方抽奖 */ + if (node.type === 'RICH_TEXT_NODE_TYPE_LOTTERY') { + obj.origin_hasOfficialLottery = true; + } + obj.origin_description += node.orig_text; + }); + } } } catch (e) { log.error('动态卡片解析', e); From 5447c9ae69c95d1647f5456dd3bd58c1524eec15 Mon Sep 17 00:00:00 2001 From: shanmite Date: Tue, 6 May 2025 15:04:19 +0800 Subject: [PATCH 52/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 685e342956..43f33ed15b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## 主要变化(2.9.5) +* f5f63bc fix: 官方抽奖判断未获取到内容 (#445) +* 1832f6d feat: 增加多账号的代理 (#433) +* 717d8cf fix: 换源gitlab + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.4) * 2f5990f fix: 动态ID字符串长度超过18 diff --git a/package.json b/package.json index 354180b943..8a953febb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.4", + "version": "2.9.5", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 533606839f5339c08e1466e0af32109a20f84bf7 Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Mon, 12 May 2025 21:00:19 +0800 Subject: [PATCH 53/74] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=80=9A?= =?UTF-8?q?=E8=BF=87uid=E7=9B=91=E8=A7=86=E8=BD=AC=E5=8F=91=E6=8A=BD?= =?UTF-8?q?=E5=A5=96=E5=8A=A8=E6=80=81=20(#449)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #447 * fix:oldparseDynamicCard已经无法获取是否抽奖 使用新版api * 当 offset 为 '0'(初始页)时,传入 offset 会报错 * 小修 --- lib/core/searcher.js | 37 +++++++++++++++++++++++-------------- lib/net/api.bili.js | 1 + lib/net/bili.js | 10 +++++----- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 5318c5e5e6..7ed0f601ea 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -62,6 +62,12 @@ function parseDynamicCard(data) { if (data?.card?.desc?.uid) { return oldParseDynamicCard(data?.card); } + + // 如果是多个 items,返回一个数组 + if (Array.isArray(data?.items)) { + return data.items.map(item => parseDynamicCard({ item })); + } + let ditem = data?.item; /**临时储存单个动态中的信息 */ let obj = {}; @@ -352,16 +358,18 @@ function oldParseDynamicCard(dynamic_detail_card) { function modifyDynamicRes(res) { let { data, code } = utils.strToJson(res), - { cards, has_more, offset } = data || {}; + { items, has_more, offset } = data || {}; if (code !== 0) { log.error('处理动态数据', '获取动态数据出错,可能是访问太频繁 \n' + res); return null; } - - if (cards == null || !cards || !cards.length) { + /** + * !cards已经能涵盖cards == null,你在想什么? + */ + if (!items || !items.length) { log.warn('处理动态数据', '未找到任何动态信息'); - cards = []; + items = []; } if (typeof has_more === 'undefined' @@ -376,18 +384,16 @@ function modifyDynamicRes(res) { */ next = { has_more, - next_offset: typeof offset === 'string' - ? offset - : /(?<=next_offset":)[0-9]+/.exec(res)[0] + next_offset: offset }, /** * 储存获取到的一组动态中的信息 */ array = next.has_more === 0 ? [] - : cards.map(oldParseDynamicCard); + : items.map(item => parseDynamicCard({ item })); - log.info('处理动态数据', `动态数据读取完毕(${cards.length})(${next.has_more})`); + log.info('处理动态数据', `动态数据读取完毕(${items.length})(${next.has_more})`); return { modifyDynamicResArray: array, @@ -408,7 +414,7 @@ class Searcher { * @param {string} [offset] 默认'0' * @returns {Promise<{allModifyDynamicResArray: UsefulDynamicInfo[], offset: string} | null>} 获取前 `pages*12` 个动态信息 */ - static async checkAllDynamic(hostuid, pages, time = 0, offset = '0') { + static async checkAllDynamic(host_mid, pages, time = 0, offset = '0') { log.info('检查所有动态', `准备读取${pages}页动态`); const { getOneDynamicInfoByUID } = bili, @@ -419,7 +425,7 @@ class Searcher { /** * 储存了特定UID的请求函数 */ - hadUidGetOneDynamicInfoByUID = curriedGetOneDynamicInfoByUID(hostuid); + hadUidGetOneDynamicInfoByUID = curriedGetOneDynamicInfoByUID(host_mid); /** * 储存所有经过整理后信息 @@ -430,9 +436,12 @@ class Searcher { for (let i = 0; i < pages; i++) { log.info('检查所有动态', `正在读取其中第${i + 1}页动态`); - const - OneDynamicInfo = await hadUidGetOneDynamicInfoByUID(offset), - mDRdata = modifyDynamicRes(OneDynamicInfo); + // 当 offset 为 '0'(初始页)时,传入 offset 会报错 + const OneDynamicInfo = offset === '0' + ? await hadUidGetOneDynamicInfoByUID() + : await hadUidGetOneDynamicInfoByUID(offset); + + const mDRdata = modifyDynamicRes(OneDynamicInfo); if (mDRdata === null) { return null; diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index 0133046d3c..dca3339bb9 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -39,4 +39,5 @@ module.exports = Object.freeze({ WEB_INTERFACE_NAV_STAT: 'https://api.bilibili.com/x/web-interface/nav/stat', WEB_INTERFACE_SEARCH_TYPE: 'https://api.bilibili.com/x/web-interface/search/type', X_POLYMER_WEB_DYNAMIC_V1_DETAIL: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/detail', + X_POLYMER_WEB_DYNAMIC_V1_FEED_SPACE: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space', }); diff --git a/lib/net/bili.js b/lib/net/bili.js index 0cc02a53bc..e55e302ac5 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -455,14 +455,14 @@ const bili_client = { * @param {string} offset_dynamic_id 此动态偏移量 初始为 0 * @returns {Promise} */ - getOneDynamicInfoByUID(host_uid, offset_dynamic_id) { + getOneDynamicInfoByUID(host_mid, offset) { /* 鉴别工作交由modifyDynamicRes完成 */ + /* 新版似乎没有 visitor_uid */ return get({ - url: API.DYNAMIC_SVR_SPACE_HISTORY, + url: API.X_POLYMER_WEB_DYNAMIC_V1_FEED_SPACE, query: { - visitor_uid: GlobalVar.get('myUID'), - host_uid, - offset_dynamic_id, + host_mid, + offset, }, config: { retry: false From f261e915f07cf2efaee3dc21d7eddddbc07df484 Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Tue, 13 May 2025 17:21:43 +0800 Subject: [PATCH 54/74] =?UTF-8?q?fix:=20API.X=5FPOLYMER=5FWEB=5FDYNAMIC=5F?= =?UTF-8?q?V1=5FDETAIL=20=E7=BC=BA=E5=B0=91=E5=8F=82=E6=95=B0=20(#452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 完善api * 小修 --------- Co-authored-by: kaban --- lib/net/api.bili.js | 1 - lib/net/bili.js | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/net/api.bili.js b/lib/net/api.bili.js index dca3339bb9..6b352c711f 100644 --- a/lib/net/api.bili.js +++ b/lib/net/api.bili.js @@ -7,7 +7,6 @@ module.exports = Object.freeze({ DYNAMIC_SVR_CREATE: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/create', DYNAMIC_SVR_GET_DYNAMIC_DETAIL: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail', DYNAMIC_SVR_RM_DYNAMIC: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/rm_dynamic', - DYNAMIC_SVR_SPACE_HISTORY: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history', FEED_GET_ATTENTION_LIST: 'https://api.vc.bilibili.com/feed/v1/feed/get_attention_list', FEED_SETUSERFOLLOW: 'https://api.vc.bilibili.com/feed/v1/feed/SetUserFollow', FETCH_SESSION_MSGS: 'https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs', diff --git a/lib/net/bili.js b/lib/net/bili.js index e55e302ac5..7b7e7cf625 100644 --- a/lib/net/bili.js +++ b/lib/net/bili.js @@ -419,7 +419,8 @@ const bili_client = { url: API.X_POLYMER_WEB_DYNAMIC_V1_DETAIL, config: { retry: false }, query: { - id + id, + features: 'itemOpusStyle' } }), (dynamic_id) => get({ From 737feae41e5e29a9f87722675953a1876b2d7aa4 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 16 May 2025 09:53:33 +0800 Subject: [PATCH 55/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43f33ed15b..49cc748eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 主要变化(2.9.6) +* f261e91 fix: API.X_POLYMER_WEB_DYNAMIC_V1_DETAIL 缺少参数 (#452) +* 5336068 fix: 修复通过uid监视转发抽奖动态 (#449) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.5) * f5f63bc fix: 官方抽奖判断未获取到内容 (#445) * 1832f6d feat: 增加多账号的代理 (#433) diff --git a/package.json b/package.json index 8a953febb1..98fbf123bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.5", + "version": "2.9.6", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From bcf87a9d00211374e5e0ef79e937d37890b70f32 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 19 May 2025 09:08:03 +0800 Subject: [PATCH 56/74] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=AD=89=E7=BA=A7Notice=20(#454)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #454 --- env.example.js | 2 +- lib/check.js | 4 ++-- lib/update.js | 2 +- lib/utils.js | 28 ++++++++++++++++++++-------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/env.example.js b/env.example.js index 9feef3c69d..e3c4427f01 100644 --- a/env.example.js +++ b/env.example.js @@ -12,7 +12,7 @@ module.exports = Object.freeze({ * - `ENABLE_MULTIPLE_ACCOUNT` 是否启用多账号 * - `MULTIPLE_ACCOUNT_PARM` 多账号参数(JSON格式) <不推荐使用 * ## 调试相关 - * - `LOTTERY_LOG_LEVEL` 输出日志等级 Error OK'); } if (desp) { - log.info('可能中奖了', desp); + log.notice('可能中奖了', desp); await sendNotify(`帐号${num}可能中奖了`, desp); } else { - log.info('中奖检测', '暂未中奖'); + log.notice('中奖检测', '暂未中奖'); } return; } diff --git a/lib/update.js b/lib/update.js index 4932844faf..4aa0e33130 100644 --- a/lib/update.js +++ b/lib/update.js @@ -83,7 +83,7 @@ async function update(isDdownload) { log.info('自动下载', '成功下载到当前目录'); log.info('检查更新', '请手动解压替换可执行文件'); } - log.info('更新说明', '\n' + text + '\n'); + log.notice('更新说明', '\n' + text + '\n'); } else { throw `未找到能在此平台(${process.platform})-(${process.arch})上运行的版本,建议以源码运行`; } diff --git a/lib/utils.js b/lib/utils.js index 66566748fd..89d0a0e6e9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -191,7 +191,7 @@ const utils = { _level: 3, _colors: [ chalk.hex('#64B3FF'), chalk.grey, chalk.hex('#FFA500'), - chalk.hex('#0070BB'), chalk.hex('#48BB31'), chalk.hex('#BBBB23'), chalk.hex('#FF0006') + chalk.hex('#0070BB'), chalk.hex('#48BB31'), chalk.hex('#BFFF00'), chalk.hex('#BBBB23'), chalk.hex('#FF0006') ], _iso_time: () => new Date(Date.now() + 288e5).toISOString().slice(0, -1) + '+08', _cache: [], @@ -231,7 +231,7 @@ const utils = { process.stdout.write(status_bar); }, debug(context, msg) { - if (this._level > 3) { + if (this._level >= 4) { if (msg instanceof Object) msg = JSON.stringify(msg, null, 4); let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], @@ -243,7 +243,7 @@ const utils = { } }, info(context, msg) { - if (this._level > 2) { + if (this._level >= 3) { let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], [this._colors[1], '[Info]'], @@ -254,25 +254,37 @@ const utils = { this.proPrint(color_text_pair.map(([color, text]) => color(text))); } }, + notice(context, msg) { + if (this._level >= 2) { + let color_text_pair = [ + [this._colors[0], `[${this._iso_time()}]`], + [this._colors[1], '[Notice]'], + [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], + [this._colors[5], `[${msg}]`], + ]; + this._cache.push(color_text_pair.map(it => it[1]).join(' ')); + this.proPrint(color_text_pair.map(([color, text]) => color(text))); + } + }, warn(context, msg) { - if (this._level > 1) { + if (this._level >= 1) { let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], [this._colors[1], '[Warn]'], [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], - [this._colors[5], `[\n${msg}\n]`], + [this._colors[6], `[\n${msg}\n]`], ]; this._cache.push(color_text_pair.map(it => it[1]).join(' ')); this.proPrint(color_text_pair.map(([color, text]) => color(text))); } }, error(context, msg) { - if (this._level > 0) { + if (this._level >= 0) { let color_text_pair = [ [this._colors[0], `[${this._iso_time()}]`], [this._colors[1], '[Error]'], [this._colors[2], `[帐号${process.env['NUMBER']} ${context}]`], - [this._colors[6], `[\n${msg}\n]`], + [this._colors[7], `[\n${msg}\n]`], ]; this._cache.push(color_text_pair.map(it => it[1]).join(' ')); this.proPrint(color_text_pair.map(([color, text]) => color(text))); @@ -475,7 +487,7 @@ const utils = { }); }); }, - getIpInfo() { + getIpInfo() { return new Promise((resolve) => { send({ url: 'https://myip.qq.com/', From e543c634041ee69e8cc2b8cc3d9e0d9505a35b06 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 19 May 2025 09:39:54 +0800 Subject: [PATCH 57/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cc748eaa..555c599ad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 主要变化(2.9.7) +* bcf87a9 feat: 新增日志等级Notice (#454) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.6) * f261e91 fix: API.X_POLYMER_WEB_DYNAMIC_V1_DETAIL 缺少参数 (#452) * 5336068 fix: 修复通过uid监视转发抽奖动态 (#449) diff --git a/package.json b/package.json index 98fbf123bc..cb8581bd0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.6", + "version": "2.9.7", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From d007d8bab9c87e6d2a5d4ca3de3d55062e297c2e Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 23 May 2025 09:33:20 +0800 Subject: [PATCH 58/74] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=8D=A2?= =?UTF-8?q?=E6=BA=90=E5=8F=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/update.js | 21 ++++++++++++--------- lib/utils.js | 6 +++++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/update.js b/lib/update.js index 4aa0e33130..2109c26308 100644 --- a/lib/update.js +++ b/lib/update.js @@ -62,21 +62,24 @@ async function update(isDdownload) { try { const { tag_name, assets, body: text } = await getLatestRelease('shanmiteko', 'LotteryAutoScript'); if (checkVersion(version) < checkVersion(tag_name)) { - const download_url = assets + /** + * @type {{browser_download_url:string, size:number}[]} + */ + const download_item = assets .filter(({ name }) => checkPlatform(name)) - .map(({ browser_download_url }) => browser_download_url); - if (download_url.length) { + .map(({ browser_download_url, size }) => { return { browser_download_url, size }; }); + if (download_item.length) { if (isDdownload) { - await try_for_each(download_url.entries(), async ([i, url]) => { - let proxy_url = 'https://mirror.ghproxy.com/'; - proxy_url += url; + await try_for_each(download_item.entries(), async ([i, { browser_download_url, size }]) => { + let proxy_url = 'https://ghfast.top/'; + proxy_url += browser_download_url; log.warn('自动下载', `切换代理${proxy_url}`); - await download(proxy_url, `latest_version${i}.zip`) + await download(proxy_url, `latest_version${i}.zip`, size) .catch(async err => { log.error('自动下载', err); - proxy_url = url; + proxy_url = browser_download_url; log.warn('自动下载', `使用原始链接${proxy_url}`); - await download(proxy_url, `latest_version${i}.zip`); + await download(proxy_url, `latest_version${i}.zip`, size); }); return false; }); diff --git a/lib/utils.js b/lib/utils.js index 89d0a0e6e9..08ad090589 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -318,9 +318,10 @@ const utils = { * 下载文件 * @param {string} url * @param {string} file_name + * @param {number} size * @returns {Promise} */ - download(url, file_name) { + download(url, file_name, size) { return new Promise((resolve, reject) => { send({ url, @@ -340,6 +341,9 @@ const utils = { resStream.pipe(wtbs); wtbs.on('finish', () => { utils.log.proPrint('下载完成'); + if (recv_length < size) { + reject(`未正确下载文件: ${recv_length}B < ${size}B`); + } resolve(); }).on('error', error => { wtbs.destroy(); From ca1ea8c93de16204535b085bceae03d3d6b15da8 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 23 May 2025 09:36:12 +0800 Subject: [PATCH 59/74] =?UTF-8?q?fix:=20=E9=9D=92=E9=BE=99=E6=8D=A2?= =?UTF-8?q?=E6=BA=90gitlab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/qinglong/init.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/script/qinglong/init.sh b/script/qinglong/init.sh index 6cc50c7a5f..827f31a070 100644 --- a/script/qinglong/init.sh +++ b/script/qinglong/init.sh @@ -4,9 +4,7 @@ set -e NAME=LotteryAutoScript BRABCH=main -# 视网络情况选择链接 -GIT_REPO=https://github.com/shanmiteko/${NAME}.git -# GIT_REPO=https://ghproxy.com/https://github.com/shanmiteko/${NAME}.git +GIT_REPO=https://gitlab.com/shanmiteko/${NAME}.git if [ -d "$NAME" ]; then cd $NAME From c4d37eda9f83f2d4b6167f0ad3ed9ea1f5a941e3 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 23 May 2025 09:42:39 +0800 Subject: [PATCH 60/74] =?UTF-8?q?fix:=20Dockerfile.pkg-arm64=E6=8D=A2?= =?UTF-8?q?=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile.pkg-arm64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.pkg-arm64 b/Dockerfile.pkg-arm64 index 80216743bc..38798ca5cb 100644 --- a/Dockerfile.pkg-arm64 +++ b/Dockerfile.pkg-arm64 @@ -5,7 +5,7 @@ WORKDIR /root/lottery RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \ apk add --no-cache curl -ENV DOWNLOAD_HOST=https://ghproxy.com/https://github.com \ +ENV DOWNLOAD_HOST=https://github.com \ RELEASE_TAG=v3.4 \ NODEV=18.5.0 \ PKG_CACHE_PATH=/root/.pkg-cache \ From c85c9106ffb775a79f7360a33857f523f76f12e4 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 23 May 2025 09:53:33 +0800 Subject: [PATCH 61/74] =?UTF-8?q?doc:=20=E5=9B=BE=E7=89=87=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E6=8D=A2=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- doc/TG_PUSH.md | 6 +++--- doc/linux_schedule.md | 2 +- doc/run_use_sc.md | 4 ++-- doc/win_schedule.md | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b943f0e4ed..6e5fa2d905 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Chrome浏览器: (此步骤是为了方便后续采用JS获取Cookies,获取完毕后应再次勾选) -![取消httponly](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/getCookies.png) +![取消httponly](doc/pic/getCookies.png) 3. 在Console中复制以下代码回车 @@ -166,7 +166,7 @@ buvid3亦可不填 使用随机生成值 ``` 1. 运行截图 - ![lottery_start](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/lottery_start.png) + ![lottery_start](doc/pic/lottery_start.png) #### 以源码方式运行 @@ -208,7 +208,7 @@ buvid3亦可不填 使用随机生成值 | :----------------: | :--------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SCKEY` | 微信server酱推送(于2021/4月下线) | server酱的微信通知[官方文档](http://sc.ftqq.com/3.version) | | `SENDKEY` | 微信server酱(Turbo版)推送 | [获取SENDKEY](https://sct.ftqq.com/sendkey) [选择消息通道](https://sct.ftqq.com/forward) | -| `BARK_PUSH` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | IOS用户下载BARK这个APP,填写内容是app提供的`设备码`,例如: ,那么此处的设备码就是`123`,再不懂看 [这个图](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/bark.jpg)(注:支持自建填完整链接即可) | +| `BARK_PUSH` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | IOS用户下载BARK这个APP,填写内容是app提供的`设备码`,例如: ,那么此处的设备码就是`123`,再不懂看 [这个图](doc/pic/bark.jpg)(注:支持自建填完整链接即可) | | `BARK_SOUND` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | bark推送声音设置,例如`choo`,具体值请在`bark`-`推送铃声`-`查看所有铃声` | | `PUSHDEER_URL` | [Pushdeer](https://github.com/easychen/pushdeer) | 推送api 默认: | | `PUSHDEER_PUSHKEY` | [Pushdeer](https://github.com/easychen/pushdeer) | PushKey | @@ -217,7 +217,7 @@ buvid3亦可不填 使用随机生成值 | `TG_PROXY_HOST` | Telegram 代理的 IP | 代理类型为 http。例子:http代理 则填写 127.0.0.1 | | `TG_PROXY_PORT` | Telegram 代理的端口 | 例子:http代理 则填写 1080 | | `DD_BOT_TOKEN` | 钉钉推送 | 钉钉推送(`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需)[官方文档](https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq) ,只需`https://oapi.dingtalk.com/robot/send?access_token=XXX` 等于`=`符号后面的XXX即可 | -| `DD_BOT_SECRET` | 钉钉推送 | (`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需) ,密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的`SECXXXXXXXXXX`等字符 , 注:钉钉机器人安全设置只需勾选`加签`即可,其他选项不要勾选,再不懂看 [这个图](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/DD_bot.png) | +| `DD_BOT_SECRET` | 钉钉推送 | (`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需) ,密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的`SECXXXXXXXXXX`等字符 , 注:钉钉机器人安全设置只需勾选`加签`即可,其他选项不要勾选,再不懂看 [这个图](doc/pic/DD_bot.png) | | `IGOT_PUSH_KEY` | iGot推送 | iGot聚合推送,支持多方式推送,确保消息可达。 [参考文档](https://wahao.github.io/Bark-MP-helper ) | | `QQ_SKEY` | 酷推(Cool Push)推送 | 推送所需的Skey,登录后获取Skey [参考文档](https://cp.xuthus.cc/) | | `QQ_MODE` | 酷推(Cool Push)推送 | 推送方式(send或group或者wx,默认send) [参考文档](https://cp.xuthus.cc/) | diff --git a/doc/TG_PUSH.md b/doc/TG_PUSH.md index 87dbe1291a..ee0eaa2d1d 100644 --- a/doc/TG_PUSH.md +++ b/doc/TG_PUSH.md @@ -4,16 +4,16 @@ Ⅰ.首先在Telegram上搜索[BotFather](https://t.me/BotFather)机器人
-![TG_PUSH1](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/TG_PUSH1.png) +![TG_PUSH1](pic/TG_PUSH1.png) Ⅱ.利用[BotFather](https://t.me/BotFather)创建一个属于自己的通知机器人,按照下图中的1、2、3步骤拿到token,格式形如```10xxx4:AAFcqxxxxgER5uw```。填入```TG_BOT_TOKEN```
-![TG_PUSH2](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/TG_PUSH2.png)
+![TG_PUSH2](pic/TG_PUSH2.png)
**新创建的机器人需要跟它发一条消息来开启对话,否则可能会遇到secret填对了但是收不到消息的情况**
Ⅲ.再次在Telegram上搜索[getuserIDbot](https://t.me/getuserIDbot)机器人,获取UserID。填入```TG_USER_ID```
-![TG_PUSH3](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/TG_PUSH3.png) +![TG_PUSH3](pic/TG_PUSH3.png) 至此,获取**TG_BOT_TOKEN**以及**TG_USER_ID**的教程结束 diff --git a/doc/linux_schedule.md b/doc/linux_schedule.md index b1839bdee2..2a1c5b1043 100644 --- a/doc/linux_schedule.md +++ b/doc/linux_schedule.md @@ -73,7 +73,7 @@ PATH=/sbin:/bin:/usr/sbin/:/usr/bin 看看有没有效果 -![image-start](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/image-start.png) +![image-start](pic/image-start.png) 7.如果本地的脚本需要更新 diff --git a/doc/run_use_sc.md b/doc/run_use_sc.md index 577f23c466..dac57ef1a2 100644 --- a/doc/run_use_sc.md +++ b/doc/run_use_sc.md @@ -4,7 +4,7 @@ step1: 下载代码到本地 [点此下载](https://github.com/shanmiteko/LotteryAutoScript/archive/refs/heads/main.zip)或如图示下载↓ -![点我加载下载操作图示](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/download.png) +![点我加载下载操作图示](pic/download.png) 下载的压缩包解压后修改env.example.js文件,详见step3 @@ -12,7 +12,7 @@ step2: 下载并安装Node.js [点此进入nodejs下载页面](http://nodejs.cn/download) -![点我加载下载nodejs操作图示](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/nodejs.png) +![点我加载下载nodejs操作图示](pic/nodejs.png) step3:修改env.example.js文件及创建运行文件(打开扩展名显示) diff --git a/doc/win_schedule.md b/doc/win_schedule.md index b2218c2695..9e99d20dcd 100644 --- a/doc/win_schedule.md +++ b/doc/win_schedule.md @@ -16,13 +16,13 @@ 7.在`操作`页面中点击`新建`,选择操作为`启动程序`,在设置里点击浏览找到`start.bat`文件并选择,在`起始于(可选)(T):`中的空白框里输入`start.bat`文件的目录地址,也就是`程序或脚本(P):`里`start.bat`的前面那一串目录地址,最后是以`\`结尾的 ,填好东西后按下面`确认` -![点我加载步骤7结果图示](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/step_menu.png) +![点我加载步骤7结果图示](pic/step_menu.png) 8.在`条件`页面中选择`网络`,设定启动条件为任何连接 9.在`设置`页面中选择如图示选项,或者不修改默认设置 -![点我加载步骤9结果图示](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/shezhi_renwu.png) +![点我加载步骤9结果图示](pic/shezhi_renwu.png) 10.最后按`确定` @@ -30,6 +30,6 @@ 最后你可以在任务列表中选择已有的任务,右边的操作框中选择`运行`点击,启动计划的任务,如下图所示 -![点我加载运行图示](https://raw.githubusercontents.com/shanmiteko/LotteryAutoScript/main/doc/pic/start_renwu.png) +![点我加载运行图示](pic/start_renwu.png) 具体看任务是否正常执行,你可以看看自己的账号动态的最新转发,运行成功每几分钟自动转发抽奖动态 From ebb561c3122210f6cf0d1935a1f98a53786624ae Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 23 May 2025 09:57:25 +0800 Subject: [PATCH 62/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 555c599ad6..129e638c34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## 主要变化(2.9.8) +* c85c910 doc: 图片链接换源 +* c4d37ed fix: Dockerfile.pkg-arm64换源 +* ca1ea8c fix: 青龙换源gitlab +* d007d8b feat: 更新换源及优化 + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.7) * bcf87a9 feat: 新增日志等级Notice (#454) diff --git a/package.json b/package.json index cb8581bd0c..2f2815b6c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.7", + "version": "2.9.8", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From b74bb02c655a044bbdf0d53ea02454a962bc859b Mon Sep 17 00:00:00 2001 From: amadeus5201 <1491459939@qq.com> Date: Fri, 8 Aug 2025 10:20:16 +0800 Subject: [PATCH 63/74] =?UTF-8?q?feat:=20ai=20=E8=AF=84=E8=AE=BA=20(#462)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: ai content * style: 更改ai调用方式 --- env.example.js | 11 +++++++++++ lib/core/monitor.js | 19 +++++++++++++++---- lib/data/env.js | 3 ++- lib/utils.js | 45 +++++++++++++++++++++++++++++++++++++++++++- my_config.example.js | 9 ++++++++- 5 files changed, 80 insertions(+), 7 deletions(-) diff --git a/env.example.js b/env.example.js index e3c4427f01..9d6109bf26 100644 --- a/env.example.js +++ b/env.example.js @@ -104,5 +104,16 @@ module.exports = Object.freeze({ SMTP_TO_USER: '', GOTIFY_URL: '', GOTIFY_APPKEY: '' + }, + + /** + * ai相关参数 + */ + ai_parm: { + //硅基流动apikey + SILICON_FLOW_API_KEY:'', + //提示词 + PROMPT:'' + } }); diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 874a91ea11..f9645f67a2 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -1,4 +1,4 @@ -const { log, hasEnv, shuffle, getRandomOne, delay, try_for_each, retryfn, appendLotteryInfoFile } = require('../utils'); +const { log, hasEnv, shuffle, getRandomOne,getAiContent, delay, try_for_each, retryfn, appendLotteryInfoFile } = require('../utils'); const { send } = require('../net/http'); const bili = require('../net/bili'); const { sendNotify } = require('../helper/notify'); @@ -281,7 +281,7 @@ class Monitor extends Searcher { reserve_lottery_wait, sneaktower, key_words, model, chatmodel, chat: chats, relay: relays, block_dynamic_type, max_create_time, is_imitator, - only_followed, at_users, blockword, blacklist, + only_followed, at_users, blockword, blacklist,use_ai_comments } = config, now_ts = Date.now() / 1000; @@ -527,8 +527,19 @@ class Monitor extends Searcher { /* 是否评论 */ if (isSendChat) { onelotteryinfo.rid = rid; - onelotteryinfo.chat = (getRandomOne(chats) || '!!!') - .replace(/\$\{uname\}/g, uname); + if (use_ai_comments) { + try { + log.info('开始获取Ai评论', `(https://t.bilibili.com/${dyid})`); + onelotteryinfo.chat = await getAiContent(lottery_info.des); + //(getRandomOne(chats) || '!!!').replace(/\$\{uname\}/g, uname); + log.info('Ai评论内容', `${onelotteryinfo.chat}`); + } catch (e) { + log.error('获取AI评论失败,使用随机评论', e); + onelotteryinfo.chat = (getRandomOne(chats) || '!!!').replace(/\$\{uname\}/g, uname); + } + } else { + onelotteryinfo.chat = (getRandomOne(chats) || '!!!').replace(/\$\{uname\}/g, uname); + } } alllotteryinfo.push(onelotteryinfo); diff --git a/lib/data/env.js b/lib/data/env.js index 992898a8d7..70d040bd72 100644 --- a/lib/data/env.js +++ b/lib/data/env.js @@ -13,7 +13,8 @@ const env = { const raw_env = this.raw_env(); this.setEnv({ ...raw_env['account_parm'], - ...raw_env['push_parm'] + ...raw_env['push_parm'], + ...raw_env['ai_parm'] }); }, /** diff --git a/lib/utils.js b/lib/utils.js index 08ad090589..c77bcd4c28 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -508,7 +508,50 @@ const utils = { }).catch((err) => { console.error('获取' + printMessage + '地址失败', err); }); - } + }, + /** + * 获取ai评论 + * @param {string} content + * @returns {Promise} + */ + getAiContent(content) { + return new Promise((resolve) => { + send({ + method: 'POST', + url: 'https://api.siliconflow.cn/v1/chat/completions', + headers: { + 'authorization': 'Bearer ' + process.env.SILICON_FLOW_API_KEY, + 'content-type': 'application/json' + }, + contents: { + model: 'Qwen/Qwen3-32B', + 'stream': false, + 'max_tokens': 512, + 'enable_thinking': true, + 'thinking_budget': 4096, + 'min_p': 0.05, + 'temperature': 0.7, + 'top_p': 0.7, + 'top_k': 50, + 'frequency_penalty': 0.5, + 'n': 1, + 'stop': [], + 'response_format': { 'type': 'text' }, + 'messages': [{ + 'role': 'system', + 'content': process.env.PROMPT + }, { 'role': 'user', 'content': content }] + }, + success: res => { + const data = utils.strToJson(res.body); + resolve(data?.choices?.[0]?.message?.content || null); + }, + failure: () => { + resolve(null); + } + }); + }); + }, }; diff --git a/my_config.example.js b/my_config.example.js index d8b727acb4..194411f86b 100644 --- a/my_config.example.js +++ b/my_config.example.js @@ -459,7 +459,14 @@ module.exports = Object.freeze({ * 1 * [1,2,4] */ - clear_dynamic_type: [1] + clear_dynamic_type: [1], + /** + * 是否使用ai评论。 + * true:使用 + * false:不使用 + * 如需使用需要再env.js配置ai_parm + */ + use_ai_comments: false }, /** From adbfb6bb38aa66651195cc32cf995170b276f367 Mon Sep 17 00:00:00 2001 From: shanmite Date: Fri, 8 Aug 2025 15:17:14 +0800 Subject: [PATCH 64/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ env.example.js | 3 +-- lib/core/monitor.js | 7 +++---- package.json | 2 +- script/build/changelog.sh | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129e638c34..da0be32fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 主要变化(2.10.0) +* b74bb02 feat: ai 评论 (#462) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.9.8) * c85c910 doc: 图片链接换源 * c4d37ed fix: Dockerfile.pkg-arm64换源 diff --git a/env.example.js b/env.example.js index 9d6109bf26..51955448de 100644 --- a/env.example.js +++ b/env.example.js @@ -110,10 +110,9 @@ module.exports = Object.freeze({ * ai相关参数 */ ai_parm: { - //硅基流动apikey + //[硅基流动](https://siliconflow.cn/) apikey SILICON_FLOW_API_KEY:'', //提示词 PROMPT:'' - } }); diff --git a/lib/core/monitor.js b/lib/core/monitor.js index f9645f67a2..b46a25bb36 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -1,4 +1,4 @@ -const { log, hasEnv, shuffle, getRandomOne,getAiContent, delay, try_for_each, retryfn, appendLotteryInfoFile } = require('../utils'); +const { log, hasEnv, shuffle, getRandomOne, getAiContent, delay, try_for_each, retryfn, appendLotteryInfoFile } = require('../utils'); const { send } = require('../net/http'); const bili = require('../net/bili'); const { sendNotify } = require('../helper/notify'); @@ -281,7 +281,7 @@ class Monitor extends Searcher { reserve_lottery_wait, sneaktower, key_words, model, chatmodel, chat: chats, relay: relays, block_dynamic_type, max_create_time, is_imitator, - only_followed, at_users, blockword, blacklist,use_ai_comments + only_followed, at_users, blockword, blacklist, use_ai_comments } = config, now_ts = Date.now() / 1000; @@ -530,8 +530,7 @@ class Monitor extends Searcher { if (use_ai_comments) { try { log.info('开始获取Ai评论', `(https://t.bilibili.com/${dyid})`); - onelotteryinfo.chat = await getAiContent(lottery_info.des); - //(getRandomOne(chats) || '!!!').replace(/\$\{uname\}/g, uname); + onelotteryinfo.chat = await getAiContent(lottery_info.des) || '!!!'; log.info('Ai评论内容', `${onelotteryinfo.chat}`); } catch (e) { log.error('获取AI评论失败,使用随机评论', e); diff --git a/package.json b/package.json index 2f2815b6c0..37936b27b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.9.8", + "version": "2.10.0", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { diff --git a/script/build/changelog.sh b/script/build/changelog.sh index b2a6ec6905..88045f5428 100644 --- a/script/build/changelog.sh +++ b/script/build/changelog.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # version: -level=patch +level=minor npm version $level \ --no-commit-hooks \ From 15c1d22469c252d32fea0d37d357ba3c74224a47 Mon Sep 17 00:00:00 2001 From: shanmite Date: Tue, 19 Aug 2025 11:18:10 +0800 Subject: [PATCH 65/74] =?UTF-8?q?fix:=20=E5=AE=98=E6=96=B9=E9=9D=9E?= =?UTF-8?q?=E5=AE=98=E6=96=B9=E6=8A=BD=E5=A5=96=E7=B1=BB=E5=9E=8B=E5=88=A4?= =?UTF-8?q?=E6=96=AD=20(#461)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #461 --- lib/core/monitor.js | 2 +- lib/core/searcher.js | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index b46a25bb36..686d4bb5c3 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -531,7 +531,7 @@ class Monitor extends Searcher { try { log.info('开始获取Ai评论', `(https://t.bilibili.com/${dyid})`); onelotteryinfo.chat = await getAiContent(lottery_info.des) || '!!!'; - log.info('Ai评论内容', `${onelotteryinfo.chat}`); + log.info('获取到Ai评论内容', `${onelotteryinfo.chat}`); } catch (e) { log.error('获取AI评论失败,使用随机评论', e); onelotteryinfo.chat = (getRandomOne(chats) || '!!!').replace(/\$\{uname\}/g, uname); diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 7ed0f601ea..02a1f2e990 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -252,6 +252,8 @@ function oldParseDynamicCard(dynamic_detail_card) { /* 定位@信息 */ obj.ctrl = (extendjsonToJson.ctrl) || []; /* 预约抽奖信息 */ + obj.reserve_id = ''; + obj.reserve_lottery_text = '信息丢失'; if (add_on_card_info.length > 0) { const [status, oid_str, text] = add_on_card_info .filter(it => typeof it.reserve_attach_card !== 'undefined' @@ -278,7 +280,7 @@ function oldParseDynamicCard(dynamic_detail_card) { obj.is_charge_lottery = true; } /* 是否有官方抽奖 */ - obj.hasOfficialLottery = extension && extension.lott && true; + obj.hasOfficialLottery = extension && extension.lott && true || false; /* 转发者的描述 纯文字内容 图片动态描述 后两个分别是视频动态的描述和视频本身的描述*/ obj.description = (item && ((item.content || '') + (item.description || ''))) @@ -288,6 +290,9 @@ function oldParseDynamicCard(dynamic_detail_card) { + (cardToJson.vest && cardToJson.vest.content || '') ) || ''; + if (obj.description.startsWith('互动抽奖 ')) { + obj.hasOfficialLottery = true; + } /* 转发 */ if (obj.type === 1) { const { origin_extension, origin, origin_extend_json = '{}' } = cardToJson @@ -308,6 +313,8 @@ function oldParseDynamicCard(dynamic_detail_card) { /* 被转发者的动态的ID !!!!此为大数需使用字符串值,不然JSON.parse()会有丢失精度 */ obj.origin_dynamic_id = desc.orig_dy_id_str; /* 预约抽奖信息 */ + obj.origin_reserve_id = ''; + obj.origin_reserve_lottery_text = '信息丢失'; if (add_on_card_info.length > 0) { const [status, oid_str, text] = add_on_card_info .filter(it => typeof it.reserve_attach_card !== 'undefined' @@ -334,7 +341,7 @@ function oldParseDynamicCard(dynamic_detail_card) { obj.origin_is_charge_lottery = true; } /* 是否有官方抽奖 */ - obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott; + obj.origin_hasOfficialLottery = origin_extension && origin_extension.lott || false; /* 被转发者的name */ obj.origin_uname = (user && (user.name || user.uname)) || ''; /* 被转发者的描述 */ @@ -342,6 +349,9 @@ function oldParseDynamicCard(dynamic_detail_card) { (item && (item.content || '' + item.description || '')) || (originToJson.dynamic || '' + originToJson.desc || '') || ''; + if (obj.origin_description.startsWith('互动抽奖 ')) { + obj.origin_hasOfficialLottery = true; + } } } catch (e) { log.error('动态卡片解析', e); @@ -364,9 +374,9 @@ function modifyDynamicRes(res) { log.error('处理动态数据', '获取动态数据出错,可能是访问太频繁 \n' + res); return null; } - /** - * !cards已经能涵盖cards == null,你在想什么? - */ + /** + * !cards已经能涵盖cards == null,你在想什么? + */ if (!items || !items.length) { log.warn('处理动态数据', '未找到任何动态信息'); items = []; @@ -438,8 +448,8 @@ class Searcher { // 当 offset 为 '0'(初始页)时,传入 offset 会报错 const OneDynamicInfo = offset === '0' - ? await hadUidGetOneDynamicInfoByUID() - : await hadUidGetOneDynamicInfoByUID(offset); + ? await hadUidGetOneDynamicInfoByUID() + : await hadUidGetOneDynamicInfoByUID(offset); const mDRdata = modifyDynamicRes(OneDynamicInfo); From 30bf989aa3965847769cfe2f1cdd3af613b91ebe Mon Sep 17 00:00:00 2001 From: shanmite Date: Tue, 19 Aug 2025 15:09:25 +0800 Subject: [PATCH 66/74] =?UTF-8?q?feat:=20ai=E8=AF=84=E8=AE=BA=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=89=80=E6=9C=89=E5=85=BC=E5=AE=B9OpenAI=20API?= =?UTF-8?q?=E7=9A=84=E5=B9=B3=E5=8F=B0=20(#463)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #463 --- README.md | 2 +- env.example.js | 29 +++++++++++++++++------------ lib/core/monitor.js | 10 +++++++--- lib/data/config.js | 6 ++++++ lib/utils.js | 34 +++++++++++++++++----------------- my_config.example.js | 40 +++++++++++++++++++++++++++++++++------- 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 6e5fa2d905..62b385b437 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ - 监控用户转发 - 监控话题页面 - 监控专栏合集 -- 自动点赞、评论、乱序转发、@好友、带话题、可选随机动态 +- 自动点赞、AI评论、乱序转发、@好友、带话题、可选随机动态 - 直播预约抽奖 - 检测是否中奖 - 已读@ diff --git a/env.example.js b/env.example.js index 51955448de..c79c1398e0 100644 --- a/env.example.js +++ b/env.example.js @@ -6,16 +6,19 @@ module.exports = Object.freeze({ * - `NUMBER` 表示是第几个账号 * - `CLEAR` 是否启用清理功能 * - `ACCOUNT_UA` 账号UA, 可在浏览器控制台输入 navigator.userAgent 查看 + * * ## 高级功能 * - `ENABLE_CHAT_CAPTCHA_OCR` 开启评论验证码识别 使用方法见README * - `CHAT_CAPTCHA_OCR_URL` 验证码识别接口 POST `url`->`code` - * - `ENABLE_MULTIPLE_ACCOUNT` 是否启用多账号 - * - `MULTIPLE_ACCOUNT_PARM` 多账号参数(JSON格式) <不推荐使用 + * - `ENABLE_AI_COMMENTS` 是否启用AI评论 + * * ## 调试相关 * - `LOTTERY_LOG_LEVEL` 输出日志等级 Error} */ - getAiContent(content) { + getAiContent(url, body, prompt, content) { return new Promise((resolve) => { send({ method: 'POST', - url: 'https://api.siliconflow.cn/v1/chat/completions', + url, headers: { - 'authorization': 'Bearer ' + process.env.SILICON_FLOW_API_KEY, + 'authorization': 'Bearer ' + process.env.AI_API_KEY, 'content-type': 'application/json' }, contents: { - model: 'Qwen/Qwen3-32B', + ...body, 'stream': false, - 'max_tokens': 512, 'enable_thinking': true, - 'thinking_budget': 4096, - 'min_p': 0.05, - 'temperature': 0.7, - 'top_p': 0.7, - 'top_k': 50, - 'frequency_penalty': 0.5, - 'n': 1, - 'stop': [], 'response_format': { 'type': 'text' }, - 'messages': [{ - 'role': 'system', - 'content': process.env.PROMPT - }, { 'role': 'user', 'content': content }] + 'messages': [ + { + 'role': 'system', + 'content': prompt + }, + { + 'role': 'user', + 'content': content + } + ] }, success: res => { const data = utils.strToJson(res.body); diff --git a/my_config.example.js b/my_config.example.js index 194411f86b..964ac76566 100644 --- a/my_config.example.js +++ b/my_config.example.js @@ -341,6 +341,19 @@ module.exports = Object.freeze({ '坚持不懈,迎难而上,开拓创新!', '[OK][OK]', '我来抽个奖', '中中中中中中', '[doge][doge][doge]', '我我我', ], + /** + * AI Chat completions参数 + * https://learn.microsoft.com/en-us/azure/ai-foundry/openai/reference#chat-completions + */ + ai_comments_parm: { + /** + * /chat/completions + */ + url: '', + body: {}, + prompt: '' + }, + /** * 是否抄热评 */ @@ -460,13 +473,6 @@ module.exports = Object.freeze({ * [1,2,4] */ clear_dynamic_type: [1], - /** - * 是否使用ai评论。 - * true:使用 - * false:不使用 - * 如需使用需要再env.js配置ai_parm - */ - use_ai_comments: false }, /** @@ -493,6 +499,26 @@ module.exports = Object.freeze({ APIs: [], + /** + * 默认为硅基流动,可以修改为其他AI服务 + */ + ai_comments_parm: { + url: 'https://api.siliconflow.cn/v1/chat/completions', + body: { + 'model': 'Qwen/Qwen3-32B', + 'max_tokens': 512, + 'enable_thinking': true, + 'thinking_budget': 4096, + 'min_p': 0.05, + 'temperature': 0.7, + 'top_p': 0.7, + 'top_k': 50, + 'frequency_penalty': 0.5, + 'n': 1, + }, + prompt: '请根据以下内容直接生成一条简短评论,无需说明信息,且不包含任何敏感词汇。' + }, + save_lottery_info_to_file: true, }, config_2: {}, From 7172e58d288eeb90444c320939955b6144f8337f Mon Sep 17 00:00:00 2001 From: shanmite Date: Tue, 19 Aug 2025 15:11:42 +0800 Subject: [PATCH 67/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ package.json | 2 +- script/build/changelog.sh | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da0be32fcb..a34c89c10c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 主要变化(2.10.1) +* 30bf989 feat: ai评论支持所有兼容OpenAI API的平台 (#463) +* 15c1d22 fix: 官方非官方抽奖类型判断 (#461) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.10.0) * b74bb02 feat: ai 评论 (#462) diff --git a/package.json b/package.json index 37936b27b3..4b4141fa51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.10.0", + "version": "2.10.1", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { diff --git a/script/build/changelog.sh b/script/build/changelog.sh index 88045f5428..b2a6ec6905 100644 --- a/script/build/changelog.sh +++ b/script/build/changelog.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # version: -level=minor +level=patch npm version $level \ --no-commit-hooks \ From a0856faa4ea012de523fb81470a52b6a78c2b8ea Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Aug 2025 15:47:48 +0800 Subject: [PATCH 68/74] =?UTF-8?q?fix:=20=E9=A3=8E=E6=8E=A7=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=8A=A8=E6=80=81=E5=86=85=E5=AE=B9=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=20(#465)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #465 --- lib/core/monitor.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index 896ac7e06f..c6b7821916 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -354,6 +354,11 @@ class Monitor extends Searcher { log.debug('正在筛选的动态信息', lottery_info); + if (des === '') { + log.info('筛选动态', `获取动态内容为空(https://t.bilibili.com/${dyid})风控`); + return false; + } + if (lottery_info_type.startsWith('sneak') && sneaktower) { log.info('筛选动态', `偷塔模式不检查是否已转发(https://t.bilibili.com/${dyid})`); } else { From d40daa2b0a16e15ca6a79a2497243d1fe27d37c6 Mon Sep 17 00:00:00 2001 From: shanmite Date: Mon, 25 Aug 2025 16:01:31 +0800 Subject: [PATCH 69/74] =?UTF-8?q?docs:=20=E6=B3=A8=E8=A7=A3=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- my_config.example.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/my_config.example.js b/my_config.example.js index 964ac76566..3397af94d5 100644 --- a/my_config.example.js +++ b/my_config.example.js @@ -483,15 +483,12 @@ module.exports = Object.freeze({ /** * 手动添加抽奖号UID * - 抽奖动态下的二级小号 + * + * 帐号1存储抽奖信息至文件 */ UIDs: [], - TAGs: [ - '互动抽奖', - '转发抽奖', - '动态抽奖', - '抽奖', - ], + TAGs: [], Articles: [ '抽奖合集' @@ -507,7 +504,6 @@ module.exports = Object.freeze({ body: { 'model': 'Qwen/Qwen3-32B', 'max_tokens': 512, - 'enable_thinking': true, 'thinking_budget': 4096, 'min_p': 0.05, 'temperature': 0.7, @@ -521,6 +517,9 @@ module.exports = Object.freeze({ save_lottery_info_to_file: true, }, + /** + * 后续帐号从文件提取抽奖信息转抽 + */ config_2: {}, config_3: {} }); From d0a0dd9219ba59f5ee1f65b4a206b4b0dd4f8d9d Mon Sep 17 00:00:00 2001 From: shanmite Date: Wed, 17 Dec 2025 08:12:11 +0800 Subject: [PATCH 70/74] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9EQMSG=5FSOCKET?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=8F=82=E6=95=B0=E6=94=AF=E6=8C=81=E7=A7=81?= =?UTF-8?q?=E6=9C=89=E4=BA=91=20(#473)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed #473 --- README.md | 61 ++++++++++++++++++++++---------------------- env.example.js | 1 + lib/helper/notify.js | 15 ++++++++--- 3 files changed, 43 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 62b385b437..def2e7e1a9 100644 --- a/README.md +++ b/README.md @@ -204,36 +204,37 @@ buvid3亦可不填 使用随机生成值 以下是支持的推送方式 -| Name | 归属 | 说明 | -| :----------------: | :--------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `SCKEY` | 微信server酱推送(于2021/4月下线) | server酱的微信通知[官方文档](http://sc.ftqq.com/3.version) | -| `SENDKEY` | 微信server酱(Turbo版)推送 | [获取SENDKEY](https://sct.ftqq.com/sendkey) [选择消息通道](https://sct.ftqq.com/forward) | -| `BARK_PUSH` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | IOS用户下载BARK这个APP,填写内容是app提供的`设备码`,例如: ,那么此处的设备码就是`123`,再不懂看 [这个图](doc/pic/bark.jpg)(注:支持自建填完整链接即可) | -| `BARK_SOUND` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | bark推送声音设置,例如`choo`,具体值请在`bark`-`推送铃声`-`查看所有铃声` | -| `PUSHDEER_URL` | [Pushdeer](https://github.com/easychen/pushdeer) | 推送api 默认: | -| `PUSHDEER_PUSHKEY` | [Pushdeer](https://github.com/easychen/pushdeer) | PushKey | -| `TG_BOT_TOKEN` | telegram推送 | tg推送(需设备可连接外网),`TG_BOT_TOKEN`和`TG_USER_ID`两者必需,填写自己申请[@BotFather](https://t.me/BotFather)的Token,如`10xxx4:AAFcqxxxxgER5uw` , [具体教程](doc/TG_PUSH.md) | -| `TG_USER_ID` | telegram推送 | tg推送(需设备可连接外网),`TG_BOT_TOKEN`和`TG_USER_ID`两者必需,填写[@getuseridbot](https://t.me/getuseridbot)中获取到的纯数字ID, [具体教程](doc/TG_PUSH.md) | -| `TG_PROXY_HOST` | Telegram 代理的 IP | 代理类型为 http。例子:http代理 则填写 127.0.0.1 | -| `TG_PROXY_PORT` | Telegram 代理的端口 | 例子:http代理 则填写 1080 | -| `DD_BOT_TOKEN` | 钉钉推送 | 钉钉推送(`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需)[官方文档](https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq) ,只需`https://oapi.dingtalk.com/robot/send?access_token=XXX` 等于`=`符号后面的XXX即可 | -| `DD_BOT_SECRET` | 钉钉推送 | (`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需) ,密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的`SECXXXXXXXXXX`等字符 , 注:钉钉机器人安全设置只需勾选`加签`即可,其他选项不要勾选,再不懂看 [这个图](doc/pic/DD_bot.png) | -| `IGOT_PUSH_KEY` | iGot推送 | iGot聚合推送,支持多方式推送,确保消息可达。 [参考文档](https://wahao.github.io/Bark-MP-helper ) | -| `QQ_SKEY` | 酷推(Cool Push)推送 | 推送所需的Skey,登录后获取Skey [参考文档](https://cp.xuthus.cc/) | -| `QQ_MODE` | 酷推(Cool Push)推送 | 推送方式(send或group或者wx,默认send) [参考文档](https://cp.xuthus.cc/) | -| `QYWX_AM` | 企业微信应用 | 第一个值是企业id,第二个值是secret,第三个值@all(或者成员id),第四个值是AgentID (逗号分割) 可查看此[教程](http://note.youdao.com/s/HMiudGkb) [官方文档](https://developer.work.weixin.qq.com/document/path/90236) | -| `QYWX_KEY` | 企业微信Bot推送 | 密钥,企业微信推送 webhook 后面的 key [详见官方说明文档](https://work.weixin.qq.com/api/doc/90000/90136/91770) | -| `PUSH_PLUS_TOKEN` | pushplus推送 | 微信扫码登录后一对一推送或一对多推送下面的token(您的Token) [官方网站](http://pushplus.hxtrip.com/) | -| `PUSH_PLUS_USER` | pushplus推送 | 一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码)注:(1、需订阅者扫描二维码 2、如果您是创建群组所属人,也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送),只填`PUSH_PLUS_TOKEN`默认为一对一推送 | -| `QMSG_KEY` | [Qmsg酱](https://qmsg.zendee.cn)私聊推送 | [Qmsg注册](https://qmsg.zendee.cn/login.html) | -| `QMSG_QQ` | 私聊消息推送接口,指定需要接收消息的QQ | 指定的QQ号必须在你的[管理台](https://qmsg.zendee.cn/me.html)已添加 | -| `SMTP_HOST` | 电子邮件 | smtp服务器的主机名 如: `smtp.qq.com` | -| `SMTP_PORT` | 电子邮件 | smtp服务器的端口 如: `465` | -| `SMTP_USER` | 电子邮件 | 发送方的电子邮件 如: `xxxxxxxxx@qq.com` | -| `SMTP_PASS` | 电子邮件 | smtp服务对应的授权码 | -| `SMTP_TO_USER` | 电子邮件 | 接收方电子邮件 | -| `GOTIFY_URL` | gotify推送 | gotify消息推送地址(例如 http://localhost:8008/message),[官方文档](https://gotify.net/docs/) | -| `GOTIFY_APPKEY` | gotify推送 | 一个gotify application的token,[官方文档](https://gotify.net/docs/) | +| Name | 归属 | 说明 | +| :----------------: | :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `SCKEY` | 微信server酱推送(于2021/4月下线) | server酱的微信通知[官方文档](http://sc.ftqq.com/3.version) | +| `SENDKEY` | 微信server酱(Turbo版)推送 | [获取SENDKEY](https://sct.ftqq.com/sendkey) [选择消息通道](https://sct.ftqq.com/forward) | +| `BARK_PUSH` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | IOS用户下载BARK这个APP,填写内容是app提供的`设备码`,例如: ,那么此处的设备码就是`123`,再不懂看 [这个图](doc/pic/bark.jpg)(注:支持自建填完整链接即可) | +| `BARK_SOUND` | [BARK推送](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | bark推送声音设置,例如`choo`,具体值请在`bark`-`推送铃声`-`查看所有铃声` | +| `PUSHDEER_URL` | [Pushdeer](https://github.com/easychen/pushdeer) | 推送api 默认: | +| `PUSHDEER_PUSHKEY` | [Pushdeer](https://github.com/easychen/pushdeer) | PushKey | +| `TG_BOT_TOKEN` | telegram推送 | tg推送(需设备可连接外网),`TG_BOT_TOKEN`和`TG_USER_ID`两者必需,填写自己申请[@BotFather](https://t.me/BotFather)的Token,如`10xxx4:AAFcqxxxxgER5uw` , [具体教程](doc/TG_PUSH.md) | +| `TG_USER_ID` | telegram推送 | tg推送(需设备可连接外网),`TG_BOT_TOKEN`和`TG_USER_ID`两者必需,填写[@getuseridbot](https://t.me/getuseridbot)中获取到的纯数字ID, [具体教程](doc/TG_PUSH.md) | +| `TG_PROXY_HOST` | Telegram 代理的 IP | 代理类型为 http。例子:http代理 则填写 127.0.0.1 | +| `TG_PROXY_PORT` | Telegram 代理的端口 | 例子:http代理 则填写 1080 | +| `DD_BOT_TOKEN` | 钉钉推送 | 钉钉推送(`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需)[官方文档](https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq) ,只需`https://oapi.dingtalk.com/robot/send?access_token=XXX` 等于`=`符号后面的XXX即可 | +| `DD_BOT_SECRET` | 钉钉推送 | (`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需) ,密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的`SECXXXXXXXXXX`等字符 , 注:钉钉机器人安全设置只需勾选`加签`即可,其他选项不要勾选,再不懂看 [这个图](doc/pic/DD_bot.png) | +| `IGOT_PUSH_KEY` | iGot推送 | iGot聚合推送,支持多方式推送,确保消息可达。 [参考文档](https://wahao.github.io/Bark-MP-helper ) | +| `QQ_SKEY` | 酷推(Cool Push)推送 | 推送所需的Skey,登录后获取Skey [参考文档](https://cp.xuthus.cc/) | +| `QQ_MODE` | 酷推(Cool Push)推送 | 推送方式(send或group或者wx,默认send) [参考文档](https://cp.xuthus.cc/) | +| `QYWX_AM` | 企业微信应用 | 第一个值是企业id,第二个值是secret,第三个值@all(或者成员id),第四个值是AgentID (逗号分割) 可查看此[教程](http://note.youdao.com/s/HMiudGkb) [官方文档](https://developer.work.weixin.qq.com/document/path/90236) | +| `QYWX_KEY` | 企业微信Bot推送 | 密钥,企业微信推送 webhook 后面的 key [详见官方说明文档](https://work.weixin.qq.com/api/doc/90000/90136/91770) | +| `PUSH_PLUS_TOKEN` | pushplus推送 | 微信扫码登录后一对一推送或一对多推送下面的token(您的Token) [官方网站](http://pushplus.hxtrip.com/) | +| `PUSH_PLUS_USER` | pushplus推送 | 一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码)注:(1、需订阅者扫描二维码 2、如果您是创建群组所属人,也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送),只填`PUSH_PLUS_TOKEN`默认为一对一推送 | +| `QMSG_SOCKET` | [Qmsg酱](https://qmsg.zendee.cn)私聊推送 | 私有云IP:私有云WEB端口 默认`qmsg.zendee.cn` | +| `QMSG_KEY` | [Qmsg酱](https://qmsg.zendee.cn)私聊推送 | [Qmsg注册](https://qmsg.zendee.cn/login.html) | +| `QMSG_QQ` | 私聊消息推送接口,指定需要接收消息的QQ | 指定的QQ号必须在你的[管理台](https://qmsg.zendee.cn/me.html)已添加 | +| `SMTP_HOST` | 电子邮件 | smtp服务器的主机名 如: `smtp.qq.com` | +| `SMTP_PORT` | 电子邮件 | smtp服务器的端口 如: `465` | +| `SMTP_USER` | 电子邮件 | 发送方的电子邮件 如: `xxxxxxxxx@qq.com` | +| `SMTP_PASS` | 电子邮件 | smtp服务对应的授权码 | +| `SMTP_TO_USER` | 电子邮件 | 接收方电子邮件 | +| `GOTIFY_URL` | gotify推送 | gotify消息推送地址(例如 http://localhost:8008/message),[官方文档](https://gotify.net/docs/) | +| `GOTIFY_APPKEY` | gotify推送 | 一个gotify application的token,[官方文档](https://gotify.net/docs/) | ---------------------------------------- diff --git a/env.example.js b/env.example.js index c79c1398e0..3b97e8f0d8 100644 --- a/env.example.js +++ b/env.example.js @@ -100,6 +100,7 @@ module.exports = Object.freeze({ IGOT_PUSH_KEY: '', PUSH_PLUS_TOKEN: '', PUSH_PLUS_USER: '', + QMSG_SOCKET: '', QMSG_KEY: '', QMSG_QQ: '', SMTP_HOST: '', diff --git a/lib/helper/notify.js b/lib/helper/notify.js index d965b1d91e..d0f13e92b9 100644 --- a/lib/helper/notify.js +++ b/lib/helper/notify.js @@ -70,6 +70,7 @@ let PUSH_PLUS_TOKEN = ''; let PUSH_PLUS_USER = ''; // ===========================================QMSG=========================================== +let QMSG_SOCKET = ''; let QMSG_KEY = ''; let QMSG_QQ = ''; @@ -173,6 +174,12 @@ if (process.env.PUSH_PLUS_USER) { PUSH_PLUS_USER = process.env.PUSH_PLUS_USER; } +if (process.env.QMSG_SOCKET) { + QMSG_SOCKET = process.env.QMSG_SOCKET; +} else { + QMSG_SOCKET = 'qmsg.zendee.cn'; +} + if (process.env.QMSG_KEY) { QMSG_KEY = process.env.QMSG_KEY; } @@ -619,7 +626,7 @@ function ddBotNotify(text, desp) { function qywxAmNotify(text, desp) { return new Promise(resolve => { - desp=desp.replace(/\n/g, '
'); + desp = desp.replace(/\n/g, '
'); if (QYWX_AM) { const QYWX_AM_AY = QYWX_AM.split(','); send({ @@ -648,8 +655,8 @@ function qywxAmNotify(text, desp) { agentid: `${QYWX_AM_AY[3]}`, safe: '0', msgtype: 'mpnews', - mpnews : { - articles:[ + mpnews: { + articles: [ { title: `${text}`, thumb_media_id: `${QYWX_AM_AY[4]}`, @@ -883,7 +890,7 @@ async function qmsg(text, desp) { if (QMSG_KEY) { send({ method: 'POST', - url: 'https://qmsg.zendee.cn/send/' + QMSG_KEY, + url: `https://${QMSG_SOCKET}/send/${QMSG_KEY}`, contents: { msg: text + '\n\n' + desp, qq: QMSG_QQ From 33a1d1a38b8f56f7cc1ed4c19e7c10a8f3501754 Mon Sep 17 00:00:00 2001 From: shanmite Date: Wed, 17 Dec 2025 08:17:09 +0800 Subject: [PATCH 71/74] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a34c89c10c..daa009b6a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## 主要变化(2.10.2) +* d0a0dd9 feat: 新增QMSG_SOCKET推送参数支持私有云 (#473) +* d40daa2 docs: 注解默认设置 +* a0856fa fix: 风控导致动态内容为空 (#465) + +_如果之前版本小于上一版本,请查看[CHANGELOG](https://github.com/shanmiteko/LotteryAutoScript/blob/main/CHANGELOG.md)变更说明_ + ## 主要变化(2.10.1) * 30bf989 feat: ai评论支持所有兼容OpenAI API的平台 (#463) * 15c1d22 fix: 官方非官方抽奖类型判断 (#461) diff --git a/package.json b/package.json index 4b4141fa51..cf11829fd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lottery-auto-script", - "version": "2.10.1", + "version": "2.10.2", "description": "自动参与B站动态抽奖", "main": "main.js", "scripts": { From 08a635957966294a122bfa4b05f6da50af944790 Mon Sep 17 00:00:00 2001 From: shanmite Date: Thu, 25 Dec 2025 08:22:57 +0800 Subject: [PATCH 72/74] =?UTF-8?q?fix:=20`is=5Fcharge=5Flottery`=E9=BB=98?= =?UTF-8?q?=E8=AE=A4false?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/searcher.js | 4 ++++ test/dyidSearch.test.js | 2 +- test/dynamic_card.test.js | 6 ++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/core/searcher.js b/lib/core/searcher.js index 02a1f2e990..27a28c5b7c 100644 --- a/lib/core/searcher.js +++ b/lib/core/searcher.js @@ -148,6 +148,7 @@ function parseDynamicCard(data) { obj.reserve_id = ditem?.modules?.module_dynamic?.additional?.reserve?.rid || 0; obj.reserve_lottery_text = ditem?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失'; /* 充电抽奖 */ + obj.is_charge_lottery = false; if (ditem?.modules?.module_dynamic?.additional?.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { obj.is_charge_lottery = true; } @@ -184,6 +185,7 @@ function parseDynamicCard(data) { obj.origin_reserve_id = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.rid || 0; obj.origin_reserve_lottery_text = ditem?.orig?.modules?.module_dynamic?.additional?.reserve?.title || '信息丢失'; /* 充电抽奖 */ + obj.origin_is_charge_lottery = false; if (ditem?.orig?.modules?.module_dynamic?.additional?.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { obj.origin_is_charge_lottery = true; } @@ -276,6 +278,7 @@ function oldParseDynamicCard(dynamic_detail_card) { obj.reserve_lottery_text = '信息丢失'; } } + obj.is_charge_lottery = false; if (extend_json.match(/"":\{"lottery/)) { obj.is_charge_lottery = true; } @@ -337,6 +340,7 @@ function oldParseDynamicCard(dynamic_detail_card) { obj.origin_reserve_lottery_text = '信息丢失'; } } + obj.origin_is_charge_lottery = false; if (origin_extend_json.match(/"":\{"lottery/)) { obj.origin_is_charge_lottery = true; } diff --git a/test/dyidSearch.test.js b/test/dyidSearch.test.js index f493c0ac03..d2a3821059 100644 --- a/test/dyidSearch.test.js +++ b/test/dyidSearch.test.js @@ -3,7 +3,7 @@ const util = require('./util'); const d_storage = require('../lib/helper/d_storage'); (async () => { - await util.par_run([0], [ + await util.par_run([], [ // 0 async () => { assert(await d_storage.searchDyid('1234567901234568')); diff --git a/test/dynamic_card.test.js b/test/dynamic_card.test.js index 010599faf7..ea307e398e 100644 --- a/test/dynamic_card.test.js +++ b/test/dynamic_card.test.js @@ -4,15 +4,17 @@ const searcher = require('../lib/core/searcher'); const util = require('./util'); (async () => { - await util.par_run([], [ + await util.par_run([0, 1], [ // 0 async () => { let info = await bili_client.getOneDynamicByDyid('728424890210713624'); assert(searcher.parseDynamicCard(info).is_charge_lottery); + info = await bili_client.getOneDynamicByDyid('1143258210499559428'); + assert(searcher.parseDynamicCard(info).is_charge_lottery); }, // 1 async () => { - let info = await bili_client.getOneDynamicByDyid('768874900850999300'); + let info = await bili_client.getOneDynamicByDyid('1150096953788334085'); assert(searcher.parseDynamicCard(info).origin_is_charge_lottery); }, // 2 From 7aa82fe412368fefee4e7c18da06e8d07f58dfce Mon Sep 17 00:00:00 2001 From: qubyyang Date: Sat, 7 Feb 2026 18:11:47 +0800 Subject: [PATCH 73/74] feat: Integrate Feishu for notification (#482) Co-authored-by: Albert Yang --- README.md | 2 ++ env.example.js | 4 ++- lib/helper/notify.js | 79 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index def2e7e1a9..6c6af8a9d6 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,8 @@ buvid3亦可不填 使用随机生成值 | `TG_PROXY_PORT` | Telegram 代理的端口 | 例子:http代理 则填写 1080 | | `DD_BOT_TOKEN` | 钉钉推送 | 钉钉推送(`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需)[官方文档](https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq) ,只需`https://oapi.dingtalk.com/robot/send?access_token=XXX` 等于`=`符号后面的XXX即可 | | `DD_BOT_SECRET` | 钉钉推送 | (`DD_BOT_TOKEN`和`DD_BOT_SECRET`两者必需) ,密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的`SECXXXXXXXXXX`等字符 , 注:钉钉机器人安全设置只需勾选`加签`即可,其他选项不要勾选,再不懂看 [这个图](doc/pic/DD_bot.png) | +| `FS_BOT_WEBHOOK` | 飞书机器人 | 飞书机器人 webhook,创建自定义机器人后复制 webhook 地址,[官方文档](https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot) | +| `FS_BOT_SECRET` | 飞书机器人 | 飞书机器人安全设置中的签名密钥(若开启“签名校验”则必填),[官方文档](https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot) | | `IGOT_PUSH_KEY` | iGot推送 | iGot聚合推送,支持多方式推送,确保消息可达。 [参考文档](https://wahao.github.io/Bark-MP-helper ) | | `QQ_SKEY` | 酷推(Cool Push)推送 | 推送所需的Skey,登录后获取Skey [参考文档](https://cp.xuthus.cc/) | | `QQ_MODE` | 酷推(Cool Push)推送 | 推送方式(send或group或者wx,默认send) [参考文档](https://cp.xuthus.cc/) | diff --git a/env.example.js b/env.example.js index 3b97e8f0d8..9532b96461 100644 --- a/env.example.js +++ b/env.example.js @@ -109,7 +109,9 @@ module.exports = Object.freeze({ SMTP_PASS: '', SMTP_TO_USER: '', GOTIFY_URL: '', - GOTIFY_APPKEY: '' + GOTIFY_APPKEY: '', + FS_BOT_WEBHOOK: '', + FS_BOT_SECRET: '' }, /** diff --git a/lib/helper/notify.js b/lib/helper/notify.js index d0f13e92b9..bd268d60f4 100644 --- a/lib/helper/notify.js +++ b/lib/helper/notify.js @@ -88,6 +88,14 @@ let GOTIFY_URL = ''; // 此处填你想推送的Application的Token(不包含推送时额外添加的前缀 Bearer ) let GOTIFY_APPKEY = ''; +// =======================================飞书机器人通知设置区域=========================================== +// 此处填你飞书机器人的 webhook(详见文档 https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot) +// 注:此处设置github action用户填写到Settings-Secrets里面(Name输入FS_BOT_WEBHOOK) +let FS_BOT_WEBHOOK = ''; +// 签名密钥(如果在飞书机器人安全设置里开启了“签名校验”) +// 注:此处设置github action用户填写到Settings-Secrets里面(Name输入FS_BOT_SECRET) +let FS_BOT_SECRET = ''; + //==========================云端环境变量的判断与接收========================= if (process.env.SCKEY) { SCKEY = process.env.SCKEY; @@ -211,6 +219,14 @@ if (process.env.GOTIFY_URL) { } } +if (process.env.FS_BOT_WEBHOOK) { + FS_BOT_WEBHOOK = process.env.FS_BOT_WEBHOOK; +} + +if (process.env.FS_BOT_SECRET) { + FS_BOT_SECRET = process.env.FS_BOT_SECRET; +} + //==========================云端环境变量的判断与接收========================= async function sendNotify(text, desp, params = {}) { @@ -246,7 +262,9 @@ async function sendNotify(text, desp, params = {}) { //电子邮件 email(text, desp), // Gotify - gotifyNotify(text, desp) + gotifyNotify(text, desp), + // 飞书机器人 + feishuNotify(text, desp) ]); } @@ -885,6 +903,65 @@ function gotifyNotify(text, desp) { }); } +function feishuNotify(text, desp) { + return new Promise(resolve => { + if (FS_BOT_WEBHOOK) { + const payload = { + msg_type: 'text', + content: { + text: `${text}\n\n${desp}` + } + }; + + if (FS_BOT_SECRET) { + const crypto = require('crypto'); + const timestamp = Math.floor(Date.now() / 1000); + const signStr = `${timestamp}\n${FS_BOT_SECRET}`; + const sign = crypto + .createHmac('sha256', FS_BOT_SECRET) + .update(signStr) + .digest('base64'); + payload.timestamp = `${timestamp}`; + payload.sign = sign; + } + + send({ + method: 'POST', + url: FS_BOT_WEBHOOK, + contents: payload, + config: { + retry: false + }, + headers: { + accept: 'application/json, text/plain, */*', + 'content-type': 'application/json', + }, + success: res => { + try { + const data = JSON.parse(res.body); + if (data.code === 0) { + log.info('发送通知', '飞书机器人发送通知消息完成。'); + } else { + log.error('发送通知', `${data.msg || '飞书机器人发送通知异常'}`); + } + } catch (e) { + log.error('发送通知', e); + } finally { + resolve(); + } + }, + failure: err => { + log.error('发送通知', '飞书机器人发送通知消息失败!!' + err); + resolve(); + } + }); + } else { + log.debug('发送通知', '您未提供飞书机器人推送所需的FS_BOT_WEBHOOK,取消飞书机器人推送消息通知'); + resolve(); + } + }); +} + async function qmsg(text, desp) { return new Promise(resolve => { if (QMSG_KEY) { From abe660b7172faf418a24f942b78ace8654fc0ef1 Mon Sep 17 00:00:00 2001 From: Violiate <166909042+Violiate@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:37:29 +0800 Subject: [PATCH 74/74] fix: prevent is_repost_then_chat from overriding AI-generated comments (#485) When AI comments are enabled and successfully generated, the is_repost_then_chat option would overwrite the AI comment with relay_chat. This fix adds an isAiChat flag so that: - When AI comment exists: relay_chat is set to the AI comment instead - When no AI comment: original behavior (chat += relay_chat) is preserved --- lib/core/monitor.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/core/monitor.js b/lib/core/monitor.js index c6b7821916..ec7ab15f45 100644 --- a/lib/core/monitor.js +++ b/lib/core/monitor.js @@ -255,6 +255,7 @@ class Monitor extends Searcher { * @property {string} [rid] 评论标识 * @property {number} chat_type 评论类型 * @property {string} [chat] 评论词 + * @property {boolean} [isAiChat] 是否为AI生成的评论 */ /** * @returns {Promise} @@ -541,6 +542,7 @@ class Monitor extends Searcher { ai_comments_parm.prompt, lottery_info.des) || '!!!'; log.info('获取到Ai评论内容', `${onelotteryinfo.chat}`); + onelotteryinfo.isAiChat = true; } catch (e) { log.error('获取AI评论失败,使用随机评论', e); onelotteryinfo.chat = (getRandomOne(chats) || '!!!').replace(/\$\{uname\}/g, uname); @@ -600,7 +602,7 @@ class Monitor extends Searcher { let status = 0, - { uid, dyid, chat_type, rid, relay_chat, ctrl, chat } = option, + { uid, dyid, chat_type, rid, relay_chat, ctrl, chat, isAiChat } = option, { check_if_duplicated, is_copy_chat, copy_blockword, is_repost_then_chat, is_not_create_partition } = config; /* 评论 */ @@ -616,7 +618,11 @@ class Monitor extends Searcher { global_var.get('myUNAME') || ''); } else { if (is_repost_then_chat) { - chat = chat + relay_chat; + if (isAiChat) { + relay_chat = chat; + } else { + chat = chat + relay_chat; + } } }