tt-help-cli-ycl 1.4.41 → 1.4.43
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/package.json +1 -1
- package/src/cli/tag.js +57 -33
- package/src/lib/args.js +5 -0
package/package.json
CHANGED
package/src/cli/tag.js
CHANGED
|
@@ -1548,7 +1548,7 @@ export async function handleTag(parsed) {
|
|
|
1548
1548
|
|
|
1549
1549
|
export async function handleTagRefresh(parsed) {
|
|
1550
1550
|
const { tagRefresh } = parsed;
|
|
1551
|
-
const { serverUrl, port, proxy: cliProxy } = tagRefresh || {};
|
|
1551
|
+
const { serverUrl, port, proxy: cliProxy, webserver } = tagRefresh || {};
|
|
1552
1552
|
|
|
1553
1553
|
const baseUrl = serverUrl || DEFAULT_SERVER;
|
|
1554
1554
|
const defaultRefreshPort =
|
|
@@ -1743,19 +1743,23 @@ export async function handleTagRefresh(parsed) {
|
|
|
1743
1743
|
const clientId = randomUUID();
|
|
1744
1744
|
const clientMeta = { type: "tag-refresh", port: cdpPort };
|
|
1745
1745
|
|
|
1746
|
-
// 复用 TikTokScraper
|
|
1747
|
-
const enrichScraper =
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1746
|
+
// 复用 TikTokScraper(webserver 模式下不需要本地 scraper)
|
|
1747
|
+
const enrichScraper = webserver
|
|
1748
|
+
? null
|
|
1749
|
+
: new TikTokScraper({
|
|
1750
|
+
poolSize: 3,
|
|
1751
|
+
proxyServer: effectiveProxy || undefined,
|
|
1752
|
+
});
|
|
1753
|
+
if (enrichScraper) {
|
|
1754
|
+
await enrichScraper.init();
|
|
1755
|
+
log("✅ TikTokScraper 已就绪 (enrich 复用)");
|
|
1756
|
+
}
|
|
1753
1757
|
log(` 客户端 ID: ${clientId.substring(0, 8)}...`);
|
|
1754
1758
|
log("");
|
|
1755
1759
|
|
|
1756
1760
|
const cleanup = () => {
|
|
1757
1761
|
log("\n正在清理资源...");
|
|
1758
|
-
enrichScraper.close().catch(() => {});
|
|
1762
|
+
if (enrichScraper) enrichScraper.close().catch(() => {});
|
|
1759
1763
|
killEdgeProcesses(null, cdpPort);
|
|
1760
1764
|
process.exit(0);
|
|
1761
1765
|
};
|
|
@@ -1875,32 +1879,52 @@ export async function handleTagRefresh(parsed) {
|
|
|
1875
1879
|
continue;
|
|
1876
1880
|
}
|
|
1877
1881
|
|
|
1878
|
-
// enrich:
|
|
1879
|
-
|
|
1880
|
-
videos,
|
|
1881
|
-
baseUrl,
|
|
1882
|
-
enrichScraper,
|
|
1883
|
-
{
|
|
1884
|
-
clientId,
|
|
1885
|
-
clientMeta,
|
|
1886
|
-
effectiveProxy,
|
|
1887
|
-
log,
|
|
1888
|
-
},
|
|
1889
|
-
);
|
|
1890
|
-
videos = enriched.videos;
|
|
1891
|
-
|
|
1892
|
-
// CDN 限流检测
|
|
1893
|
-
const cdnBlocked = enriched.cdnBlockedCount || 0;
|
|
1894
|
-
if (cdnBlocked > 0) {
|
|
1895
|
-
const cdnRatio = cdnBlocked / (videos.length || 1);
|
|
1896
|
-
const coolSec = cdnRatio > 0.3 ? 120 : 60;
|
|
1882
|
+
// enrich: webserver API 或本地 HTTP view-source
|
|
1883
|
+
if (webserver) {
|
|
1897
1884
|
log(
|
|
1898
|
-
`
|
|
1885
|
+
` ⏳ 补充国家信息 (${videos.length} 个视频, via webserver ${webserver})...`,
|
|
1899
1886
|
);
|
|
1900
|
-
await
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1887
|
+
await enrichViaWebserver(
|
|
1888
|
+
videos,
|
|
1889
|
+
webserver,
|
|
1890
|
+
({ done, total, current, locationCreated }) => {
|
|
1891
|
+
if (done % 10 === 0 || done === total) {
|
|
1892
|
+
const name = current.split("/").pop().slice(0, 20);
|
|
1893
|
+
process.stderr.write(
|
|
1894
|
+
`\r [${done}/${total}] ${name} → ${locationCreated || "-"}\x1b[K`,
|
|
1895
|
+
);
|
|
1896
|
+
}
|
|
1897
|
+
},
|
|
1898
|
+
);
|
|
1899
|
+
process.stderr.write("\n");
|
|
1900
|
+
} else {
|
|
1901
|
+
// enrich: 先查服务端缓存,只对未知视频发 HTTP 请求
|
|
1902
|
+
const enriched = await enrichWithServerCache(
|
|
1903
|
+
videos,
|
|
1904
|
+
baseUrl,
|
|
1905
|
+
enrichScraper,
|
|
1906
|
+
{
|
|
1907
|
+
clientId,
|
|
1908
|
+
clientMeta,
|
|
1909
|
+
effectiveProxy,
|
|
1910
|
+
log,
|
|
1911
|
+
},
|
|
1912
|
+
);
|
|
1913
|
+
videos = enriched.videos;
|
|
1914
|
+
|
|
1915
|
+
// CDN 限流检测
|
|
1916
|
+
const cdnBlocked = enriched.cdnBlockedCount || 0;
|
|
1917
|
+
if (cdnBlocked > 0) {
|
|
1918
|
+
const cdnRatio = cdnBlocked / (videos.length || 1);
|
|
1919
|
+
const coolSec = cdnRatio > 0.3 ? 120 : 60;
|
|
1920
|
+
log(
|
|
1921
|
+
` ⚠️ CDN 限流: ${cdnBlocked}/${videos.length} (${(cdnRatio * 100).toFixed(0)}%),冷却 ${coolSec} 秒后重启 scraper`,
|
|
1922
|
+
);
|
|
1923
|
+
await new Promise((r) => setTimeout(r, coolSec * 1000));
|
|
1924
|
+
log(` 正在重启 TikTokScraper...`);
|
|
1925
|
+
await enrichScraper.restart();
|
|
1926
|
+
log(` ✅ TikTokScraper 已重启`);
|
|
1927
|
+
}
|
|
1904
1928
|
}
|
|
1905
1929
|
|
|
1906
1930
|
// 过滤目标国家的视频和作者
|
package/src/lib/args.js
CHANGED
|
@@ -181,6 +181,7 @@ function parseExploreArgs(args) {
|
|
|
181
181
|
let exploreUserId = null;
|
|
182
182
|
let exploreMaxVideos = 16;
|
|
183
183
|
let exploreProxy = null;
|
|
184
|
+
let exploreWebserver = null;
|
|
184
185
|
|
|
185
186
|
const positional = [];
|
|
186
187
|
const PRESETS = ["fast", "normal", "slow", "stealth"];
|
|
@@ -221,6 +222,8 @@ function parseExploreArgs(args) {
|
|
|
221
222
|
exploreMaxVideos = parseInt(args[++i]) || 16;
|
|
222
223
|
} else if (arg === "--proxy") {
|
|
223
224
|
exploreProxy = args[++i];
|
|
225
|
+
} else if (arg === "--webserver") {
|
|
226
|
+
exploreWebserver = args[++i];
|
|
224
227
|
} else {
|
|
225
228
|
positional.push(arg);
|
|
226
229
|
}
|
|
@@ -262,6 +265,7 @@ function parseExploreArgs(args) {
|
|
|
262
265
|
exploreUserId,
|
|
263
266
|
exploreMaxVideos,
|
|
264
267
|
exploreProxy,
|
|
268
|
+
exploreWebserver,
|
|
265
269
|
urls: [],
|
|
266
270
|
outputFormat: "json",
|
|
267
271
|
exploreCount: 0,
|
|
@@ -1155,6 +1159,7 @@ function parseTagArgs(args) {
|
|
|
1155
1159
|
serverUrl,
|
|
1156
1160
|
port: refreshPort,
|
|
1157
1161
|
proxy: scoreProxy,
|
|
1162
|
+
webserver: webserverUrl,
|
|
1158
1163
|
},
|
|
1159
1164
|
urls: [],
|
|
1160
1165
|
outputFormat: "json",
|