@luoyi-dsh/instagram-scroll 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +171 -2
- package/README.zh-Hant.md +174 -0
- package/client.js +1146 -0
- package/cordis.patch.yml +9 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +83 -0
- package/dist/config.js.map +1 -0
- package/dist/core/scrollDuty.d.ts +29 -0
- package/dist/core/scrollDuty.d.ts.map +1 -0
- package/dist/core/scrollDuty.js +185 -0
- package/dist/core/scrollDuty.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +249 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/hostdeps.d.ts +5 -0
- package/dist/lib/hostdeps.d.ts.map +1 -0
- package/dist/lib/hostdeps.js +28 -0
- package/dist/lib/hostdeps.js.map +1 -0
- package/dist/lib/ledger.d.ts +55 -0
- package/dist/lib/ledger.d.ts.map +1 -0
- package/dist/lib/ledger.js +140 -0
- package/dist/lib/ledger.js.map +1 -0
- package/dist/tools/scrollTools.d.ts +7 -0
- package/dist/tools/scrollTools.d.ts.map +1 -0
- package/dist/tools/scrollTools.js +82 -0
- package/dist/tools/scrollTools.js.map +1 -0
- package/package.json +65 -5
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# dsh-instagram-scroll —— DSH bundle patch(插件掛載宣告)
|
|
3
|
+
# ============================================================================
|
|
4
|
+
|
|
5
|
+
- insert:
|
|
6
|
+
- id: instagram-scroll
|
|
7
|
+
name: '@luoyi-dsh/instagram-scroll'
|
|
8
|
+
config:
|
|
9
|
+
enabled: true
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/config.ts —— Instagram 滾動探索與主人推坑插件設定
|
|
3
|
+
*/
|
|
4
|
+
export interface InstagramScrollConfig {
|
|
5
|
+
masterUsername?: string;
|
|
6
|
+
interestTags?: string[];
|
|
7
|
+
personaPrompt?: string;
|
|
8
|
+
minScore?: number;
|
|
9
|
+
dailyRecommendCap?: number;
|
|
10
|
+
scrollIntervalMinutes?: number;
|
|
11
|
+
autoScrollEnabled?: boolean;
|
|
12
|
+
likeOnRecommend?: boolean;
|
|
13
|
+
batchSize?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const defaultScrollConfig: InstagramScrollConfig;
|
|
16
|
+
export declare function unwrapScrollValue<T>(val: any, fallback: T): T;
|
|
17
|
+
export declare function sanitizeScrollConfig(raw: any): InstagramScrollConfig;
|
|
18
|
+
export declare function buildScrollConfigSchema(z: any): any;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,mBAAmB,EAAE,qBAWjC,CAAA;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAW7D;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,qBAAqB,CAapE;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,GAAG,OAuC7C"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/config.ts —— Instagram 滾動探索與主人推坑插件設定
|
|
3
|
+
*/
|
|
4
|
+
export const defaultScrollConfig = {
|
|
5
|
+
masterUsername: '',
|
|
6
|
+
interestTags: ['ai', 'deepseek', 'coding', 'tech', 'gadgets'],
|
|
7
|
+
personaPrompt: '你是一位洞察力敏銳、品味高雅的社群特助。請評估這篇 Instagram 貼文/影片是否具有前沿乾貨、創意見解、實用價值或視覺驚艷。若是主人會感興趣的好內容,請給出大於80分的評價,並撰寫簡短自然、熱情真誠的推坑一句話。',
|
|
8
|
+
minScore: 75,
|
|
9
|
+
dailyRecommendCap: 5,
|
|
10
|
+
scrollIntervalMinutes: 60,
|
|
11
|
+
autoScrollEnabled: true,
|
|
12
|
+
likeOnRecommend: true,
|
|
13
|
+
batchSize: 15,
|
|
14
|
+
};
|
|
15
|
+
export function unwrapScrollValue(val, fallback) {
|
|
16
|
+
if (val === null || val === undefined)
|
|
17
|
+
return fallback;
|
|
18
|
+
if (val === '[object Object]')
|
|
19
|
+
return fallback;
|
|
20
|
+
if (typeof val === 'object' && typeof val.get === 'function') {
|
|
21
|
+
const v = val.get();
|
|
22
|
+
return (v !== undefined && v !== null && typeof v !== 'object') ? v : fallback;
|
|
23
|
+
}
|
|
24
|
+
if (typeof val === 'object' && !Array.isArray(val)) {
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
return val;
|
|
28
|
+
}
|
|
29
|
+
export function sanitizeScrollConfig(raw) {
|
|
30
|
+
const c = raw || {};
|
|
31
|
+
return {
|
|
32
|
+
masterUsername: unwrapScrollValue(c.masterUsername, defaultScrollConfig.masterUsername || ''),
|
|
33
|
+
interestTags: Array.isArray(c.interestTags) ? c.interestTags : (defaultScrollConfig.interestTags || []),
|
|
34
|
+
personaPrompt: unwrapScrollValue(c.personaPrompt, defaultScrollConfig.personaPrompt || ''),
|
|
35
|
+
minScore: unwrapScrollValue(c.minScore, defaultScrollConfig.minScore || 75),
|
|
36
|
+
dailyRecommendCap: unwrapScrollValue(c.dailyRecommendCap, defaultScrollConfig.dailyRecommendCap || 5),
|
|
37
|
+
scrollIntervalMinutes: unwrapScrollValue(c.scrollIntervalMinutes, defaultScrollConfig.scrollIntervalMinutes || 60),
|
|
38
|
+
autoScrollEnabled: unwrapScrollValue(c.autoScrollEnabled, defaultScrollConfig.autoScrollEnabled ?? true),
|
|
39
|
+
likeOnRecommend: unwrapScrollValue(c.likeOnRecommend, defaultScrollConfig.likeOnRecommend ?? true),
|
|
40
|
+
batchSize: unwrapScrollValue(c.batchSize, defaultScrollConfig.batchSize || 15),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function buildScrollConfigSchema(z) {
|
|
44
|
+
return z.object({
|
|
45
|
+
masterUsername: z
|
|
46
|
+
.string()
|
|
47
|
+
.default('')
|
|
48
|
+
.description('主人的 Instagram 使用者名稱 (發現好文時將在留言區 @主人推薦)'),
|
|
49
|
+
interestTags: z
|
|
50
|
+
.array(z.string())
|
|
51
|
+
.default(['ai', 'deepseek', 'coding', 'tech'])
|
|
52
|
+
.description('主人感興趣的主題標籤或領域關鍵字清單'),
|
|
53
|
+
personaPrompt: z
|
|
54
|
+
.string()
|
|
55
|
+
.default(defaultScrollConfig.personaPrompt)
|
|
56
|
+
.description('評估貼文趣味度與撰寫 @主人推薦語的人設提示詞'),
|
|
57
|
+
minScore: z
|
|
58
|
+
.number()
|
|
59
|
+
.default(75)
|
|
60
|
+
.description('推坑門檻分數 (0-100,達標才在貼文下留言 @主人)'),
|
|
61
|
+
dailyRecommendCap: z
|
|
62
|
+
.number()
|
|
63
|
+
.default(5)
|
|
64
|
+
.description('每日向主人推坑留言的上限則數 (防止過度頻繁打擾與風控)'),
|
|
65
|
+
scrollIntervalMinutes: z
|
|
66
|
+
.number()
|
|
67
|
+
.default(60)
|
|
68
|
+
.description('自動刷動態牆並尋找好內容的時間週期 (分鐘)'),
|
|
69
|
+
autoScrollEnabled: z
|
|
70
|
+
.boolean()
|
|
71
|
+
.default(true)
|
|
72
|
+
.description('是否啟用背景定時自動刷動態牆任務'),
|
|
73
|
+
likeOnRecommend: z
|
|
74
|
+
.boolean()
|
|
75
|
+
.default(true)
|
|
76
|
+
.description('決定推薦給主人時是否順便對該貼文點讚'),
|
|
77
|
+
batchSize: z
|
|
78
|
+
.number()
|
|
79
|
+
.default(15)
|
|
80
|
+
.description('每輪滾動瀏覽抓取的貼文筆數 (10-30)'),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,MAAM,CAAC,MAAM,mBAAmB,GAA0B;IACxD,cAAc,EAAE,EAAE;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;IAC7D,aAAa,EACX,+GAA+G;IACjH,QAAQ,EAAE,EAAE;IACZ,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,EAAE;IACzB,iBAAiB,EAAE,IAAI;IACvB,eAAe,EAAE,IAAI;IACrB,SAAS,EAAE,EAAE;CACd,CAAA;AAED,MAAM,UAAU,iBAAiB,CAAI,GAAQ,EAAE,QAAW;IACxD,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAA;IACtD,IAAI,GAAG,KAAK,iBAAiB;QAAE,OAAO,QAAQ,CAAA;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;QAC7D,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,EAAE,CAAA;QACnB,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;IAChF,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,OAAO,GAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAQ;IAC3C,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAA;IACnB,OAAO;QACL,cAAc,EAAE,iBAAiB,CAAC,CAAC,CAAC,cAAc,EAAE,mBAAmB,CAAC,cAAc,IAAI,EAAE,CAAC;QAC7F,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,YAAY,IAAI,EAAE,CAAC;QACvG,aAAa,EAAE,iBAAiB,CAAC,CAAC,CAAC,aAAa,EAAE,mBAAmB,CAAC,aAAa,IAAI,EAAE,CAAC;QAC1F,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,IAAI,EAAE,CAAC;QAC3E,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,iBAAiB,IAAI,CAAC,CAAC;QACrG,qBAAqB,EAAE,iBAAiB,CAAC,CAAC,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,qBAAqB,IAAI,EAAE,CAAC;QAClH,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,iBAAiB,IAAI,IAAI,CAAC;QACxG,eAAe,EAAE,iBAAiB,CAAC,CAAC,CAAC,eAAe,EAAE,mBAAmB,CAAC,eAAe,IAAI,IAAI,CAAC;QAClG,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,SAAS,EAAE,mBAAmB,CAAC,SAAS,IAAI,EAAE,CAAC;KAC/E,CAAA;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,CAAM;IAC5C,OAAO,CAAC,CAAC,MAAM,CAAC;QACd,cAAc,EAAE,CAAC;aACd,MAAM,EAAE;aACR,OAAO,CAAC,EAAE,CAAC;aACX,WAAW,CAAC,wCAAwC,CAAC;QACxD,YAAY,EAAE,CAAC;aACZ,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,OAAO,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;aAC7C,WAAW,CAAC,oBAAoB,CAAC;QACpC,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,OAAO,CAAC,mBAAmB,CAAC,aAAc,CAAC;aAC3C,WAAW,CAAC,yBAAyB,CAAC;QACzC,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,OAAO,CAAC,EAAE,CAAC;aACX,WAAW,CAAC,8BAA8B,CAAC;QAC9C,iBAAiB,EAAE,CAAC;aACjB,MAAM,EAAE;aACR,OAAO,CAAC,CAAC,CAAC;aACV,WAAW,CAAC,8BAA8B,CAAC;QAC9C,qBAAqB,EAAE,CAAC;aACrB,MAAM,EAAE;aACR,OAAO,CAAC,EAAE,CAAC;aACX,WAAW,CAAC,wBAAwB,CAAC;QACxC,iBAAiB,EAAE,CAAC;aACjB,OAAO,EAAE;aACT,OAAO,CAAC,IAAI,CAAC;aACb,WAAW,CAAC,kBAAkB,CAAC;QAClC,eAAe,EAAE,CAAC;aACf,OAAO,EAAE;aACT,OAAO,CAAC,IAAI,CAAC;aACb,WAAW,CAAC,oBAAoB,CAAC;QACpC,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,OAAO,CAAC,EAAE,CAAC;aACX,WAAW,CAAC,uBAAuB,CAAC;KACxC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/scrollDuty.ts —— Instagram 滾動探索、趣味評估與 @主人推坑任務
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* 概念參照 dsh-bili-scroll:
|
|
5
|
+
* 每天替主人刷一輪 Instagram(時間軸動態 + 興趣主題探索)。
|
|
6
|
+
* 逐條讀內文判斷是否值得,遇到真心覺得主人會喜歡的貼文或影片,
|
|
7
|
+
* 就在該貼文底下留一條評論「@主人 + 推薦原因」,並記錄至今日日報。
|
|
8
|
+
* ============================================================================
|
|
9
|
+
*/
|
|
10
|
+
import type { InstagramMcpClient } from '@luoyi-dsh/instagram-mcp';
|
|
11
|
+
import { InstagramScrollConfig } from '../config.js';
|
|
12
|
+
import { ScrollLedgerManager } from '../lib/ledger.js';
|
|
13
|
+
export interface ScrollRoundResult {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
totalScanned: number;
|
|
16
|
+
worthyCount: number;
|
|
17
|
+
recommendedCount: number;
|
|
18
|
+
recommendations: Array<{
|
|
19
|
+
postPk: string;
|
|
20
|
+
code: string;
|
|
21
|
+
author: string;
|
|
22
|
+
url: string;
|
|
23
|
+
score: number;
|
|
24
|
+
comment: string;
|
|
25
|
+
}>;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function executeScrollRound(ctx: any, config: InstagramScrollConfig, mcp: InstagramMcpClient, ledger: ScrollLedgerManager, log?: (msg: string) => void): Promise<ScrollRoundResult>;
|
|
29
|
+
//# sourceMappingURL=scrollDuty.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollDuty.d.ts","sourceRoot":"","sources":["../../src/core/scrollDuty.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAiB,MAAM,0BAA0B,CAAA;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAEtD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAA;IACX,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,KAAK,CAAC;QACrB,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,MAAM,CAAA;QACd,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;IACF,OAAO,EAAE,MAAM,CAAA;CAChB;AAuED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,qBAAqB,EAC7B,GAAG,EAAE,kBAAkB,EACvB,MAAM,EAAE,mBAAmB,EAC3B,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAkB,GACvC,OAAO,CAAC,iBAAiB,CAAC,CA2H5B"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/scrollDuty.ts —— Instagram 滾動探索、趣味評估與 @主人推坑任務
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* 概念參照 dsh-bili-scroll:
|
|
5
|
+
* 每天替主人刷一輪 Instagram(時間軸動態 + 興趣主題探索)。
|
|
6
|
+
* 逐條讀內文判斷是否值得,遇到真心覺得主人會喜歡的貼文或影片,
|
|
7
|
+
* 就在該貼文底下留一條評論「@主人 + 推薦原因」,並記錄至今日日報。
|
|
8
|
+
* ============================================================================
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 簡易而實用的評估與推薦語產生器
|
|
12
|
+
* 結合貼文內文關鍵字權重、互動熱度與語意提示進行評分
|
|
13
|
+
*/
|
|
14
|
+
function evaluatePost(post, config) {
|
|
15
|
+
const caption = (post.caption || '').toLowerCase();
|
|
16
|
+
const tags = config.interestTags || [];
|
|
17
|
+
let score = 50;
|
|
18
|
+
// 1. 關鍵字與標籤匹配加分
|
|
19
|
+
let hitTags = [];
|
|
20
|
+
for (const tag of tags) {
|
|
21
|
+
const clean = tag.replace(/^#/, '').toLowerCase().trim();
|
|
22
|
+
if (clean && caption.includes(clean)) {
|
|
23
|
+
hitTags.push(clean);
|
|
24
|
+
score += 12;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// 2. 互動熱度與品質加分
|
|
28
|
+
const likes = post.like_count || 0;
|
|
29
|
+
const comments = post.comment_count || 0;
|
|
30
|
+
if (likes > 500)
|
|
31
|
+
score += 10;
|
|
32
|
+
else if (likes > 100)
|
|
33
|
+
score += 5;
|
|
34
|
+
if (comments > 20)
|
|
35
|
+
score += 8;
|
|
36
|
+
else if (comments > 5)
|
|
37
|
+
score += 4;
|
|
38
|
+
// 3. 內文長度加分(有原創詳細說明通常更具乾貨)
|
|
39
|
+
if (caption.length > 100)
|
|
40
|
+
score += 8;
|
|
41
|
+
// 4. 廣告或過濾詞扣分
|
|
42
|
+
const spamKeywords = ['互粉', '代購', '博彩', '運彩', '兼職', '抽獎', '免費領'];
|
|
43
|
+
for (const kw of spamKeywords) {
|
|
44
|
+
if (caption.includes(kw)) {
|
|
45
|
+
score -= 35;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
score = Math.min(98, Math.max(20, score));
|
|
49
|
+
const isWorthy = score >= (config.minScore || 75);
|
|
50
|
+
let reason = '';
|
|
51
|
+
let commentText = '';
|
|
52
|
+
const master = (config.masterUsername || '').replace(/^@/, '').trim();
|
|
53
|
+
if (isWorthy) {
|
|
54
|
+
if (hitTags.length > 0) {
|
|
55
|
+
reason = `精準命中主人關注領域 [#${hitTags.join(', #')}],內容高質且社群互動熱絡 (${likes} 讚, ${comments} 則留言)。`;
|
|
56
|
+
const hookPhrases = [
|
|
57
|
+
'這篇思路與案例很不錯,特別推薦你看一下!',
|
|
58
|
+
'發現這個很對你的胃口,覺得對你手邊專案很有幫助!',
|
|
59
|
+
'這篇乾貨滿滿,看到覺得不能錯過,推推!',
|
|
60
|
+
'這篇分析非常到位,特地 @ 你存起來參考!',
|
|
61
|
+
];
|
|
62
|
+
const chosenHook = hookPhrases[Math.floor(Math.random() * hookPhrases.length)];
|
|
63
|
+
commentText = master ? `@${master} ${chosenHook}` : `這篇乾貨非常精彩,推薦關注!`;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
reason = `熱門高讚貼文 (${likes} 讚),討論熱烈,具備高參考價值。`;
|
|
67
|
+
commentText = master ? `@${master} 看到這篇討論很熱絡,分享給你看看!` : '推薦這篇精彩內容!';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { isWorthy, score, reason, commentText };
|
|
71
|
+
}
|
|
72
|
+
export async function executeScrollRound(ctx, config, mcp, ledger, log = console.log) {
|
|
73
|
+
log('[ScrollDuty] 🚀 開始替主人刷一輪 Instagram...');
|
|
74
|
+
const master = (config.masterUsername || '').replace(/^@/, '').trim();
|
|
75
|
+
if (!master) {
|
|
76
|
+
log('[ScrollDuty] ⚠️ 尚未配置主人帳號 (masterUsername),將僅進行瀏覽紀錄而不留言 @主人。');
|
|
77
|
+
}
|
|
78
|
+
const batchSize = Math.max(5, config.batchSize || 15);
|
|
79
|
+
const candidatePosts = [];
|
|
80
|
+
// 1. 抓取時間軸首頁動態 (Feed)
|
|
81
|
+
try {
|
|
82
|
+
log(`[ScrollDuty] 正在滾動時間軸動態牆 (抓取上限: ${batchSize})...`);
|
|
83
|
+
const feedRes = await mcp.igGetTimelineFeed(batchSize);
|
|
84
|
+
if (feedRes?.ok && Array.isArray(feedRes.posts)) {
|
|
85
|
+
candidatePosts.push(...feedRes.posts);
|
|
86
|
+
log(`[ScrollDuty] 從首頁時間軸獲取到 ${feedRes.posts.length} 則動態。`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
log(`[ScrollDuty] 獲取時間軸動態異常: ${e.message}`);
|
|
91
|
+
}
|
|
92
|
+
// 2. 隨機選取一個主人感興趣的標籤進行主題探索 (Explore Tag)
|
|
93
|
+
const tags = config.interestTags || [];
|
|
94
|
+
if (tags.length > 0) {
|
|
95
|
+
const randomTag = tags[Math.floor(Math.random() * tags.length)].replace(/^#/, '').trim();
|
|
96
|
+
try {
|
|
97
|
+
log(`[ScrollDuty] 正在探索主題標籤 #${randomTag}...`);
|
|
98
|
+
const tagRes = await mcp.igSearchHashtag(randomTag, 10);
|
|
99
|
+
if (tagRes?.ok && Array.isArray(tagRes.posts)) {
|
|
100
|
+
candidatePosts.push(...tagRes.posts);
|
|
101
|
+
log(`[ScrollDuty] 從 #${randomTag} 獲取到 ${tagRes.posts.length} 則主題貼文。`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
log(`[ScrollDuty] 探索標籤異常: ${e.message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
let totalScanned = 0;
|
|
109
|
+
let worthyCount = 0;
|
|
110
|
+
let recommendedCount = 0;
|
|
111
|
+
const recommendations = [];
|
|
112
|
+
// 3. 逐條讀內文進行評估與推薦
|
|
113
|
+
for (const post of candidatePosts) {
|
|
114
|
+
const postPk = String(post.pk || post.id || '');
|
|
115
|
+
if (!postPk)
|
|
116
|
+
continue;
|
|
117
|
+
// 跳過已看過的貼文
|
|
118
|
+
if (ledger.hasSeen(postPk)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
totalScanned++;
|
|
122
|
+
const evalRes = evaluatePost(post, config);
|
|
123
|
+
if (evalRes.isWorthy) {
|
|
124
|
+
worthyCount++;
|
|
125
|
+
log(`[ScrollDuty] ⭐ 發現值得內容!作者: @${post.user?.username || 'unknown'}, 評分: ${evalRes.score}/100. 短碼: ${post.code}`);
|
|
126
|
+
// 檢查是否還能推坑 (每日上限控制)
|
|
127
|
+
const cap = config.dailyRecommendCap || 5;
|
|
128
|
+
if (ledger.canRecommend(cap) && master) {
|
|
129
|
+
log(`[ScrollDuty] 正在貼文下留言 @${master} 進行推薦...`);
|
|
130
|
+
try {
|
|
131
|
+
const commentRes = await mcp.igPostComment({
|
|
132
|
+
media_pk: postPk,
|
|
133
|
+
text: evalRes.commentText,
|
|
134
|
+
});
|
|
135
|
+
if (commentRes?.ok) {
|
|
136
|
+
log(`[ScrollDuty] ✅ 成功留言 @${master}!`);
|
|
137
|
+
recommendedCount++;
|
|
138
|
+
// 若開啟,順便點讚
|
|
139
|
+
if (config.likeOnRecommend) {
|
|
140
|
+
await mcp.igLikeMedia(postPk).catch(() => { });
|
|
141
|
+
}
|
|
142
|
+
const recItem = {
|
|
143
|
+
postPk,
|
|
144
|
+
code: post.code,
|
|
145
|
+
author: post.user?.username || 'unknown',
|
|
146
|
+
url: post.url || `https://www.instagram.com/p/${post.code}/`,
|
|
147
|
+
score: evalRes.score,
|
|
148
|
+
reason: evalRes.reason,
|
|
149
|
+
commentText: evalRes.commentText,
|
|
150
|
+
timestamp: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
ledger.recordRecommendation(recItem);
|
|
153
|
+
recommendations.push(recItem);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
log(`[ScrollDuty] 留言發布失敗: ${commentRes?.error || '未知原因'}`);
|
|
157
|
+
ledger.markSeen(postPk, true);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
log(`[ScrollDuty] 留言異常: ${e.message}`);
|
|
162
|
+
ledger.markSeen(postPk, true);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
log(`[ScrollDuty] 今日推薦已達上限 (${cap}則) 或未配置主人帳號,僅標記值得並記錄日報。`);
|
|
167
|
+
ledger.markSeen(postPk, true);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
ledger.markSeen(postPk, false);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const msg = `本輪滾動瀏覽完畢!共掃描 ${totalScanned} 則新內容,發現 ${worthyCount} 則值得貼文,成功替主人留評推薦 ${recommendedCount} 則。`;
|
|
175
|
+
log(`[ScrollDuty] 🎉 ${msg}`);
|
|
176
|
+
return {
|
|
177
|
+
ok: true,
|
|
178
|
+
totalScanned,
|
|
179
|
+
worthyCount,
|
|
180
|
+
recommendedCount,
|
|
181
|
+
recommendations,
|
|
182
|
+
message: msg,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=scrollDuty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollDuty.js","sourceRoot":"","sources":["../../src/core/scrollDuty.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/index.ts —— DSH Instagram 滾動瀏覽與推坑插件 (Cordis Plugin)
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* 職責:
|
|
5
|
+
* 1. 導出標準 DSH 插件結構 (name, inject, Config, apply)。
|
|
6
|
+
* 2. 依賴 dsh-instagram-mcp 核心服務 (ctx.instagramMcp),共享 FastMCP 與登入 Session。
|
|
7
|
+
* 3. 具備如同 dsh-bili-scroll 的核心能力:
|
|
8
|
+
* - 定時或手動替主人刷一輪 Instagram (首頁動態 + 主題標籤探索)
|
|
9
|
+
* - 逐條讀內文評估主人是否感興趣
|
|
10
|
+
* - 若值得,自動在該貼文底下留言 @主人 + 推薦詞,並給予點讚
|
|
11
|
+
* - 生成本日探索日報 data/reports/YYYY-MM-DD.md
|
|
12
|
+
* 4. 透過 webServer.register 官方路由標準提供 API 供 client.js 前端面板操作。
|
|
13
|
+
* ============================================================================
|
|
14
|
+
*/
|
|
15
|
+
import { InstagramScrollConfig } from './config.js';
|
|
16
|
+
export declare const name = "instagram-scroll";
|
|
17
|
+
export declare const inject: string[];
|
|
18
|
+
export declare const Config: any;
|
|
19
|
+
export declare function apply(ctx: any, userConfig?: Partial<InstagramScrollConfig>): void;
|
|
20
|
+
declare const _default: {
|
|
21
|
+
name: string;
|
|
22
|
+
inject: string[];
|
|
23
|
+
Config: any;
|
|
24
|
+
apply: typeof apply;
|
|
25
|
+
};
|
|
26
|
+
export default _default;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,EAAgD,qBAAqB,EAAwB,MAAM,aAAa,CAAA;AAMvH,eAAO,MAAM,IAAI,qBAAqB,CAAA;AACtC,eAAO,MAAM,MAAM,UAAyB,CAAA;AAG5C,eAAO,MAAM,MAAM,KAAqC,CAAA;AAoBxD,wBAAgB,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,GAAE,OAAO,CAAC,qBAAqB,CAAM,QAoN9E;;;;;;;AAED,wBAKC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/index.ts —— DSH Instagram 滾動瀏覽與推坑插件 (Cordis Plugin)
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* 職責:
|
|
5
|
+
* 1. 導出標準 DSH 插件結構 (name, inject, Config, apply)。
|
|
6
|
+
* 2. 依賴 dsh-instagram-mcp 核心服務 (ctx.instagramMcp),共享 FastMCP 與登入 Session。
|
|
7
|
+
* 3. 具備如同 dsh-bili-scroll 的核心能力:
|
|
8
|
+
* - 定時或手動替主人刷一輪 Instagram (首頁動態 + 主題標籤探索)
|
|
9
|
+
* - 逐條讀內文評估主人是否感興趣
|
|
10
|
+
* - 若值得,自動在該貼文底下留言 @主人 + 推薦詞,並給予點讚
|
|
11
|
+
* - 生成本日探索日報 data/reports/YYYY-MM-DD.md
|
|
12
|
+
* 4. 透過 webServer.register 官方路由標準提供 API 供 client.js 前端面板操作。
|
|
13
|
+
* ============================================================================
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { buildScrollConfigSchema, defaultScrollConfig, sanitizeScrollConfig } from './config.js';
|
|
19
|
+
import { loadSchemastery } from './lib/hostdeps.js';
|
|
20
|
+
import { ScrollLedgerManager } from './lib/ledger.js';
|
|
21
|
+
import { executeScrollRound } from './core/scrollDuty.js';
|
|
22
|
+
import { getSharedMcpClient, getSharedMcpService } from '@luoyi-dsh/instagram-mcp';
|
|
23
|
+
export const name = 'instagram-scroll';
|
|
24
|
+
export const inject = ['webServer', 'tools'];
|
|
25
|
+
const zInstance = await loadSchemastery();
|
|
26
|
+
export const Config = buildScrollConfigSchema(zInstance);
|
|
27
|
+
function sendJson(res, status, data) {
|
|
28
|
+
res.statusCode = status;
|
|
29
|
+
res.setHeader('content-type', 'application/json; charset=utf-8');
|
|
30
|
+
res.end(JSON.stringify(data));
|
|
31
|
+
}
|
|
32
|
+
function readBody(req) {
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
let body = '';
|
|
35
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
36
|
+
req.on('end', () => {
|
|
37
|
+
try {
|
|
38
|
+
resolve(body ? JSON.parse(body) : {});
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
resolve({});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
req.on('error', () => resolve({}));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function apply(ctx, userConfig = {}) {
|
|
48
|
+
const pluginRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
49
|
+
const dataDir = join(pluginRoot, 'data');
|
|
50
|
+
const reportsDir = join(dataDir, 'reports');
|
|
51
|
+
if (!existsSync(dataDir))
|
|
52
|
+
mkdirSync(dataDir, { recursive: true });
|
|
53
|
+
if (!existsSync(reportsDir))
|
|
54
|
+
mkdirSync(reportsDir, { recursive: true });
|
|
55
|
+
const configFile = join(dataDir, 'config.json');
|
|
56
|
+
const localSavedConfig = (() => {
|
|
57
|
+
try {
|
|
58
|
+
if (existsSync(configFile)) {
|
|
59
|
+
return JSON.parse(readFileSync(configFile, 'utf-8'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
return {};
|
|
64
|
+
})();
|
|
65
|
+
const activeConfig = sanitizeScrollConfig({
|
|
66
|
+
...defaultScrollConfig,
|
|
67
|
+
...userConfig,
|
|
68
|
+
...localSavedConfig,
|
|
69
|
+
});
|
|
70
|
+
// 若 config.json 尚不存在,動態創建初始配置檔
|
|
71
|
+
if (!existsSync(configFile)) {
|
|
72
|
+
try {
|
|
73
|
+
writeFileSync(configFile, JSON.stringify(activeConfig, null, 2), 'utf-8');
|
|
74
|
+
}
|
|
75
|
+
catch { }
|
|
76
|
+
}
|
|
77
|
+
const saveConfig = (patch) => {
|
|
78
|
+
Object.assign(activeConfig, patch);
|
|
79
|
+
try {
|
|
80
|
+
writeFileSync(configFile, JSON.stringify(activeConfig, null, 2), 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
log(`保存 config.json 失敗: ${e.message}`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const log = (msg) => {
|
|
87
|
+
console.log(`[IG-Scroll] ${msg}`);
|
|
88
|
+
};
|
|
89
|
+
log(`Instagram 滾動探索推坑插件啟動中... (路徑: ${pluginRoot})`);
|
|
90
|
+
// 初始化去重與日報帳本
|
|
91
|
+
const ledger = new ScrollLedgerManager(join(dataDir, 'scroll_ledger.json'), reportsDir);
|
|
92
|
+
let scrollTimer = null;
|
|
93
|
+
let isDisposed = false;
|
|
94
|
+
const getMcpClient = () => {
|
|
95
|
+
return getSharedMcpClient();
|
|
96
|
+
};
|
|
97
|
+
// 註冊給主模型的 DSH Tools
|
|
98
|
+
const tools = (typeof ctx.get === 'function' ? ctx.get('tools') : undefined) || ctx.tools;
|
|
99
|
+
const registerTool = (toolDef) => {
|
|
100
|
+
try {
|
|
101
|
+
if (typeof tools?.register === 'function') {
|
|
102
|
+
tools.register(toolDef);
|
|
103
|
+
}
|
|
104
|
+
else if (typeof ctx?.tool === 'function') {
|
|
105
|
+
ctx.tool(toolDef);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch { }
|
|
109
|
+
};
|
|
110
|
+
registerTool({
|
|
111
|
+
name: 'ig_run_scroll_duty_now',
|
|
112
|
+
description: '替主人在 Instagram 刷一輪動態與感興趣的熱門貼文/影片,讀取內文評估是否值得,若符合主人興趣則自動在該貼文下留言 @主人 進行推薦。',
|
|
113
|
+
parameters: { type: 'object', properties: {} },
|
|
114
|
+
execute: async () => {
|
|
115
|
+
const client = getMcpClient();
|
|
116
|
+
if (!client || !client.ready) {
|
|
117
|
+
return { ok: false, error: 'Instagram FastMCP 尚未就緒,請檢查帳號登入狀態。' };
|
|
118
|
+
}
|
|
119
|
+
return await executeScrollRound(ctx, activeConfig, client, ledger, log);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
// 排程管理器
|
|
123
|
+
const setupScheduler = () => {
|
|
124
|
+
if (isDisposed)
|
|
125
|
+
return;
|
|
126
|
+
if (scrollTimer) {
|
|
127
|
+
clearInterval(scrollTimer);
|
|
128
|
+
scrollTimer = null;
|
|
129
|
+
}
|
|
130
|
+
if (activeConfig.autoScrollEnabled) {
|
|
131
|
+
const intervalMs = Math.max(10, activeConfig.scrollIntervalMinutes || 60) * 60 * 1000;
|
|
132
|
+
log(`啟動 Instagram 自動滾動巡邏排程,週期: ${activeConfig.scrollIntervalMinutes} 分鐘`);
|
|
133
|
+
scrollTimer = setInterval(async () => {
|
|
134
|
+
const client = getMcpClient();
|
|
135
|
+
if (isDisposed || !client || !client.ready)
|
|
136
|
+
return;
|
|
137
|
+
try {
|
|
138
|
+
await executeScrollRound(ctx, activeConfig, client, ledger, log);
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
log(`自動滾動巡查執行異常: ${e.message}`);
|
|
142
|
+
}
|
|
143
|
+
}, intervalMs);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
setupScheduler();
|
|
147
|
+
// Web API 路由處理函數
|
|
148
|
+
const handleRequest = async (req, res) => {
|
|
149
|
+
try {
|
|
150
|
+
const url = new URL(req.url, 'http://127.0.0.1');
|
|
151
|
+
const pathname = url.pathname;
|
|
152
|
+
// 讀取設定
|
|
153
|
+
if (req.method === 'GET' && pathname === '/api/instagram/scroll/config') {
|
|
154
|
+
return sendJson(res, 200, { ok: true, config: sanitizeScrollConfig(activeConfig) });
|
|
155
|
+
}
|
|
156
|
+
// 儲存設定
|
|
157
|
+
if (req.method === 'POST' && pathname === '/api/instagram/scroll/config') {
|
|
158
|
+
const newCfg = await readBody(req);
|
|
159
|
+
saveConfig(newCfg);
|
|
160
|
+
setupScheduler();
|
|
161
|
+
return sendJson(res, 200, { ok: true, config: sanitizeScrollConfig(activeConfig) });
|
|
162
|
+
}
|
|
163
|
+
// 讀取今日狀態與推坑數據
|
|
164
|
+
if (req.method === 'GET' && pathname === '/api/instagram/scroll/status') {
|
|
165
|
+
const svc = getSharedMcpService() || globalThis.__DSH_INSTAGRAM_MCP__;
|
|
166
|
+
const client = getMcpClient() || svc?.client;
|
|
167
|
+
const mcpLogin = svc?.loginStatus || null;
|
|
168
|
+
const isReady = Boolean(client && client.ready);
|
|
169
|
+
const account = mcpLogin?.username ||
|
|
170
|
+
(mcpLogin?.message?.match(/@([^\s)]+)/)?.[1]) ||
|
|
171
|
+
(isReady ? '已連線' : '');
|
|
172
|
+
return sendJson(res, 200, {
|
|
173
|
+
ok: true,
|
|
174
|
+
mcpReady: isReady,
|
|
175
|
+
inheritedSession: true,
|
|
176
|
+
loginStatus: mcpLogin || (isReady ? { ok: true, message: 'FastMCP 運行中', username: account } : null),
|
|
177
|
+
mcpAccount: account,
|
|
178
|
+
dailyStats: ledger.getDailyStats(),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// 讀取今日日報內容
|
|
182
|
+
if (req.method === 'GET' && pathname === '/api/instagram/scroll/report') {
|
|
183
|
+
return sendJson(res, 200, {
|
|
184
|
+
ok: true,
|
|
185
|
+
report: ledger.getTodayReport(),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// 手動立即跑一輪
|
|
189
|
+
if (req.method === 'POST' && pathname === '/api/instagram/scroll/run') {
|
|
190
|
+
const client = getMcpClient();
|
|
191
|
+
if (!client || !client.ready) {
|
|
192
|
+
return sendJson(res, 503, { ok: false, error: 'Instagram FastMCP 尚未就緒,請先確認登入。' });
|
|
193
|
+
}
|
|
194
|
+
const result = await executeScrollRound(ctx, activeConfig, client, ledger, log);
|
|
195
|
+
return sendJson(res, 200, result);
|
|
196
|
+
}
|
|
197
|
+
sendJson(res, 404, { ok: false, error: `Not found: ${pathname}` });
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
sendJson(res, 500, { ok: false, error: err.message });
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
globalThis.__DSH_IG_SCROLL_HANDLER__ = handleRequest;
|
|
204
|
+
const webServer = (typeof ctx.get === 'function' ? ctx.get('webServer') : undefined) || ctx.webServer;
|
|
205
|
+
if (!globalThis.__DSH_IG_SCROLL_ROUTES_REGISTERED__ && webServer) {
|
|
206
|
+
const routeDispatcher = (req, res) => {
|
|
207
|
+
const activeHandler = globalThis.__DSH_IG_SCROLL_HANDLER__;
|
|
208
|
+
if (typeof activeHandler === 'function') {
|
|
209
|
+
return activeHandler(req, res);
|
|
210
|
+
}
|
|
211
|
+
return handleRequest(req, res);
|
|
212
|
+
};
|
|
213
|
+
try {
|
|
214
|
+
if (typeof webServer.register === 'function') {
|
|
215
|
+
webServer.register({
|
|
216
|
+
kind: 'prefix',
|
|
217
|
+
path: '/api/instagram/scroll',
|
|
218
|
+
handler: routeDispatcher,
|
|
219
|
+
});
|
|
220
|
+
globalThis.__DSH_IG_SCROLL_ROUTES_REGISTERED__ = true;
|
|
221
|
+
log('✅ 已註冊 DSH 官方路由: /api/instagram/scroll');
|
|
222
|
+
}
|
|
223
|
+
else if (webServer.router) {
|
|
224
|
+
webServer.router.all('/api/instagram/scroll/*', routeDispatcher);
|
|
225
|
+
globalThis.__DSH_IG_SCROLL_ROUTES_REGISTERED__ = true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (e) {
|
|
229
|
+
log(`註冊 Scroll Web 路由異常: ${e.message}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// 優雅關閉
|
|
233
|
+
const dispose = async () => {
|
|
234
|
+
isDisposed = true;
|
|
235
|
+
if (scrollTimer)
|
|
236
|
+
clearInterval(scrollTimer);
|
|
237
|
+
log('Instagram 滾動探索插件已卸載。');
|
|
238
|
+
};
|
|
239
|
+
if (typeof ctx?.on === 'function') {
|
|
240
|
+
ctx.on('dispose', dispose);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export default {
|
|
244
|
+
name,
|
|
245
|
+
inject,
|
|
246
|
+
Config,
|
|
247
|
+
apply,
|
|
248
|
+
};
|
|
249
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|