tt-help-cli-ycl 1.3.55 → 1.3.57
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/open.js +3 -4
- package/src/scraper/explore-core.js +2 -0
- package/src/watch/data-store.js +427 -101
- package/src/watch/public/index.html +110 -16
- package/src/watch/server.js +45 -3
- package/scripts/run-explore copy.bat +0 -101
- package/scripts/test-captcha-lib.mjs +0 -68
- package/scripts/test-captcha.mjs +0 -81
- package/scripts/test-html-analysis.mjs +0 -128
- package/scripts/test-incognito-lib.mjs +0 -36
- package/scripts/test-login-state.mjs +0 -128
- package/scripts/test-safe-click.mjs +0 -45
- package/scripts/test-watch-db-smoke.mjs +0 -246
package/package.json
CHANGED
package/src/cli/open.js
CHANGED
|
@@ -34,14 +34,13 @@ export async function handleOpen(parsed) {
|
|
|
34
34
|
console.error("用法: tt-help open <端口>");
|
|
35
35
|
console.error("示例: tt-help open 9222");
|
|
36
36
|
console.error("");
|
|
37
|
-
console.error("
|
|
38
|
-
console.error('运行 "tt-help open --list" 查看所有配置');
|
|
37
|
+
console.error('运行 "tt-help open --list" 查看内置浏览器配置');
|
|
39
38
|
process.exit(1);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
const port = parseInt(openPort);
|
|
43
|
-
if (isNaN(port) || port <
|
|
44
|
-
console.error(`端口 ${openPort}
|
|
42
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
43
|
+
console.error(`端口 ${openPort} 无效 (请使用 1 - 65535)`);
|
|
45
44
|
process.exit(1);
|
|
46
45
|
}
|
|
47
46
|
|
|
@@ -38,6 +38,7 @@ async function processExplore(page, username, options, log) {
|
|
|
38
38
|
keepFollow: false,
|
|
39
39
|
locationCreated: null,
|
|
40
40
|
noVideo: false,
|
|
41
|
+
restricted: false,
|
|
41
42
|
error: null,
|
|
42
43
|
};
|
|
43
44
|
|
|
@@ -172,6 +173,7 @@ async function processExplore(page, username, options, log) {
|
|
|
172
173
|
result.videoList = videoArray;
|
|
173
174
|
} else {
|
|
174
175
|
// 国家不匹配
|
|
176
|
+
result.restricted = true;
|
|
175
177
|
result.keepFollow = false;
|
|
176
178
|
result.discoveredFollowing = [];
|
|
177
179
|
result.discoveredFollowers = [];
|
package/src/watch/data-store.js
CHANGED
|
@@ -1168,6 +1168,17 @@ function getRawJobsPageFromDb({ search, location, limit, offset }) {
|
|
|
1168
1168
|
};
|
|
1169
1169
|
}
|
|
1170
1170
|
|
|
1171
|
+
// 调试接口:直接执行 SQL 查询,返回原始数据
|
|
1172
|
+
function rawQuery(sql, params = []) {
|
|
1173
|
+
if (!db) return { error: "db not ready" };
|
|
1174
|
+
try {
|
|
1175
|
+
const rows = db.prepare(sql).all(...params);
|
|
1176
|
+
return { rows };
|
|
1177
|
+
} catch (e) {
|
|
1178
|
+
return { error: e.message };
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1171
1182
|
function getUsersPageFromDb({
|
|
1172
1183
|
status,
|
|
1173
1184
|
search,
|
|
@@ -1838,12 +1849,15 @@ export function createStore(filePath) {
|
|
|
1838
1849
|
const args = [];
|
|
1839
1850
|
if (!loggedIn) {
|
|
1840
1851
|
where.push("COALESCE(tt_seller, 0) != 1");
|
|
1841
|
-
//
|
|
1842
|
-
where.push("status_code IS NULL");
|
|
1852
|
+
// 未登录:只能领取 status_code 为空或 0 的任务
|
|
1853
|
+
where.push("(status_code IS NULL OR status_code = 0)");
|
|
1843
1854
|
} else {
|
|
1844
|
-
//
|
|
1845
|
-
where.push(
|
|
1855
|
+
// 登录:可以领取 status_code 为空、0、或 209002 的任务
|
|
1856
|
+
where.push(
|
|
1857
|
+
"(status_code IS NULL OR status_code = 0 OR status_code = 209002)",
|
|
1858
|
+
);
|
|
1846
1859
|
}
|
|
1860
|
+
// 其他 status_code 值的任务不被领取
|
|
1847
1861
|
if (requireVideo) {
|
|
1848
1862
|
where.push("COALESCE(video_count, 0) > 0");
|
|
1849
1863
|
}
|
|
@@ -2020,124 +2034,433 @@ export function createStore(filePath) {
|
|
|
2020
2034
|
return null;
|
|
2021
2035
|
}
|
|
2022
2036
|
|
|
2023
|
-
|
|
2037
|
+
if (!db) {
|
|
2038
|
+
const now = Date.now();
|
|
2024
2039
|
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2040
|
+
// 0. 该客户端有未过期的任务,续期返回
|
|
2041
|
+
const ongoing = data.find(
|
|
2042
|
+
(u) =>
|
|
2043
|
+
u.status === "processing" &&
|
|
2044
|
+
u.claimedBy === userId &&
|
|
2045
|
+
u.claimedAt &&
|
|
2046
|
+
now - u.claimedAt < expireMs,
|
|
2047
|
+
);
|
|
2048
|
+
if (ongoing) {
|
|
2049
|
+
ongoing.claimedAt = now;
|
|
2050
|
+
save();
|
|
2051
|
+
return {
|
|
2052
|
+
uniqueId: ongoing.uniqueId,
|
|
2053
|
+
nickname: ongoing.nickname,
|
|
2054
|
+
claimedAt: ongoing.claimedAt,
|
|
2055
|
+
claimedBy: userId,
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2043
2058
|
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2059
|
+
// 按猜测国家梯队排序
|
|
2060
|
+
const tier1 = new Set(["PL", "NL", "BE"]);
|
|
2061
|
+
const tier2 = new Set(["DE", "FR", "IT", "IE", "ES"]);
|
|
2062
|
+
function locationTier(u) {
|
|
2063
|
+
const loc = (u.guessedLocation || "").toUpperCase();
|
|
2064
|
+
if (tier1.has(loc)) return 0;
|
|
2065
|
+
if (tier2.has(loc)) return 1;
|
|
2066
|
+
return 2;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// 国家过滤:如果指定了 locations,只保留 guessedLocation 在列表中的用户
|
|
2070
|
+
function locationFilter(u) {
|
|
2071
|
+
if (!locations || locations.length === 0) return true;
|
|
2072
|
+
return isLocationInList(u.guessedLocation, locations);
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
// 从候选列表中按优先级取第一个:pinned > 超时回收 > seed > ttSeller(仅登录) > follow > other
|
|
2076
|
+
function pickCandidate(candidates) {
|
|
2077
|
+
let next = candidates.find((u) => u.pinned);
|
|
2078
|
+
|
|
2079
|
+
if (!next) {
|
|
2080
|
+
const expired = data.find(
|
|
2081
|
+
(u) =>
|
|
2082
|
+
u.status === "processing" &&
|
|
2083
|
+
u.claimedAt &&
|
|
2084
|
+
now - u.claimedAt > expireMs,
|
|
2085
|
+
);
|
|
2086
|
+
if (expired) {
|
|
2087
|
+
expired.status = "pending";
|
|
2088
|
+
markStatsDirty();
|
|
2089
|
+
delete expired.claimedAt;
|
|
2090
|
+
next = expired;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
if (!next) {
|
|
2095
|
+
const seed = candidates.filter(
|
|
2096
|
+
(u) => u.sources && u.sources.includes("seed"),
|
|
2097
|
+
);
|
|
2098
|
+
seed.sort((a, b) => locationTier(a) - locationTier(b));
|
|
2099
|
+
next = seed[0] || null;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
// 未登录时跳过 ttSeller 优先级
|
|
2103
|
+
if (!next && loggedIn) {
|
|
2104
|
+
const ttSeller = candidates.filter(
|
|
2105
|
+
(u) => u.ttSeller === true && u.verified === false,
|
|
2106
|
+
);
|
|
2107
|
+
ttSeller.sort((a, b) => locationTier(a) - locationTier(b));
|
|
2108
|
+
next = ttSeller[0] || null;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
if (!next) {
|
|
2112
|
+
const follow = candidates.filter(
|
|
2113
|
+
(u) =>
|
|
2114
|
+
u.sources &&
|
|
2115
|
+
(u.sources.includes("following") ||
|
|
2116
|
+
u.sources.includes("follower")),
|
|
2117
|
+
);
|
|
2118
|
+
follow.sort((a, b) => locationTier(a) - locationTier(b));
|
|
2119
|
+
next = follow[0] || null;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
if (!next) {
|
|
2123
|
+
candidates.sort((a, b) => locationTier(a) - locationTier(b));
|
|
2124
|
+
next = candidates[0] || null;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
return next;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
// 先在有视频的 pending 用户中找;找不到再用全部 pending 用户兜底
|
|
2131
|
+
let pending = data.filter((u) => u.status === "pending");
|
|
2132
|
+
// 应用国家过滤
|
|
2133
|
+
if (locations && locations.length > 0) {
|
|
2134
|
+
pending = pending.filter(locationFilter);
|
|
2135
|
+
}
|
|
2136
|
+
// 未登录客户端不能领取 ttSeller 用户
|
|
2137
|
+
if (!loggedIn) {
|
|
2138
|
+
pending = pending.filter((u) => u.ttSeller !== true);
|
|
2139
|
+
}
|
|
2140
|
+
// status_code 过滤:只领取空值、0 或 209002 的任务
|
|
2141
|
+
pending = pending.filter(
|
|
2142
|
+
(u) =>
|
|
2143
|
+
u.statusCode == null ||
|
|
2144
|
+
u.statusCode === 0 ||
|
|
2145
|
+
(loggedIn && u.statusCode === 209002),
|
|
2146
|
+
);
|
|
2147
|
+
let hasVideo = pending.filter((u) => u.videoCount > 0);
|
|
2148
|
+
const next = pickCandidate(hasVideo) || pickCandidate(pending);
|
|
2053
2149
|
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2150
|
+
if (next) {
|
|
2151
|
+
next.status = "processing";
|
|
2152
|
+
markStatsDirty();
|
|
2153
|
+
next.claimedAt = now;
|
|
2154
|
+
next.claimedBy = userId;
|
|
2155
|
+
save();
|
|
2156
|
+
return {
|
|
2157
|
+
uniqueId: next.uniqueId,
|
|
2158
|
+
nickname: next.nickname,
|
|
2159
|
+
claimedAt: next.claimedAt,
|
|
2160
|
+
claimedBy: userId,
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
return null;
|
|
2058
2164
|
}
|
|
2059
2165
|
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
let next = candidates.find((u) => u.pinned);
|
|
2166
|
+
return null;
|
|
2167
|
+
}
|
|
2063
2168
|
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2169
|
+
function debugClaimNextJob(
|
|
2170
|
+
userId,
|
|
2171
|
+
expireMs = 5 * 60 * 1000,
|
|
2172
|
+
locations = null,
|
|
2173
|
+
loggedIn = true,
|
|
2174
|
+
) {
|
|
2175
|
+
if (db) {
|
|
2176
|
+
const now = Date.now();
|
|
2177
|
+
const info = {
|
|
2178
|
+
path: "db",
|
|
2179
|
+
userId,
|
|
2180
|
+
expireMs,
|
|
2181
|
+
loggedIn,
|
|
2182
|
+
};
|
|
2183
|
+
|
|
2184
|
+
const ongoingRow = db
|
|
2185
|
+
.prepare(
|
|
2186
|
+
`
|
|
2187
|
+
SELECT *
|
|
2188
|
+
FROM jobs
|
|
2189
|
+
WHERE status = 'processing'
|
|
2190
|
+
AND claimed_by = ?
|
|
2191
|
+
AND claimed_at IS NOT NULL
|
|
2192
|
+
AND ? - claimed_at < ?
|
|
2193
|
+
ORDER BY claimed_at DESC
|
|
2194
|
+
LIMIT 1
|
|
2195
|
+
`,
|
|
2196
|
+
)
|
|
2197
|
+
.get(userId, now, expireMs);
|
|
2198
|
+
info.ongoing = ongoingRow
|
|
2199
|
+
? {
|
|
2200
|
+
uniqueId: ongoingRow.unique_id,
|
|
2201
|
+
claimedBy: ongoingRow.claimed_by,
|
|
2202
|
+
claimedAt: ongoingRow.claimed_at,
|
|
2203
|
+
}
|
|
2204
|
+
: null;
|
|
2205
|
+
|
|
2206
|
+
const tier1 = new Set(["PL", "NL", "BE"]);
|
|
2207
|
+
const tier2 = new Set(["DE", "FR", "IT", "IE", "ES"]);
|
|
2208
|
+
const normalizedLocations = Array.isArray(locations)
|
|
2209
|
+
? locations
|
|
2210
|
+
.map((loc) => String(loc).trim().toUpperCase())
|
|
2211
|
+
.filter(Boolean)
|
|
2212
|
+
: [];
|
|
2213
|
+
|
|
2214
|
+
function getLocationGroups() {
|
|
2215
|
+
const selected = normalizedLocations.length
|
|
2216
|
+
? normalizedLocations
|
|
2217
|
+
: null;
|
|
2218
|
+
const tier1List = selected
|
|
2219
|
+
? selected.filter((loc) => tier1.has(loc))
|
|
2220
|
+
: [...tier1];
|
|
2221
|
+
const tier2List = selected
|
|
2222
|
+
? selected.filter((loc) => tier2.has(loc))
|
|
2223
|
+
: [...tier2];
|
|
2224
|
+
const otherList = selected
|
|
2225
|
+
? selected.filter((loc) => !tier1.has(loc) && !tier2.has(loc))
|
|
2226
|
+
: null;
|
|
2227
|
+
const groups = [];
|
|
2228
|
+
if (tier1List.length > 0)
|
|
2229
|
+
groups.push({ type: "include", values: tier1List });
|
|
2230
|
+
if (tier2List.length > 0)
|
|
2231
|
+
groups.push({ type: "include", values: tier2List });
|
|
2232
|
+
if (selected) {
|
|
2233
|
+
if (otherList.length > 0)
|
|
2234
|
+
groups.push({ type: "include", values: otherList });
|
|
2235
|
+
} else {
|
|
2236
|
+
groups.push({ type: "exclude", values: [...tier1, ...tier2] });
|
|
2076
2237
|
}
|
|
2238
|
+
return groups;
|
|
2077
2239
|
}
|
|
2078
2240
|
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2241
|
+
const locationGroups = getLocationGroups();
|
|
2242
|
+
info.locationGroups = locationGroups;
|
|
2243
|
+
|
|
2244
|
+
function applyLocationGroup(where, args, group) {
|
|
2245
|
+
if (!group) return;
|
|
2246
|
+
if (group.type === "include") {
|
|
2247
|
+
where.push(
|
|
2248
|
+
`UPPER(COALESCE(guessed_location, '')) IN (${group.values.map(() => "?").join(", ")})`,
|
|
2249
|
+
);
|
|
2250
|
+
args.push(...group.values);
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
2253
|
+
where.push(
|
|
2254
|
+
`UPPER(COALESCE(guessed_location, '')) NOT IN (${group.values.map(() => "?").join(", ")})`,
|
|
2082
2255
|
);
|
|
2083
|
-
|
|
2084
|
-
next = seed[0] || null;
|
|
2256
|
+
args.push(...group.values);
|
|
2085
2257
|
}
|
|
2086
2258
|
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
const
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2259
|
+
function queryPendingOne({ requireVideo, group, filters = [] }) {
|
|
2260
|
+
const where = ["status = 'pending'"];
|
|
2261
|
+
const args = [];
|
|
2262
|
+
if (!loggedIn) {
|
|
2263
|
+
where.push("COALESCE(tt_seller, 0) != 1");
|
|
2264
|
+
where.push("(status_code IS NULL OR status_code = 0)");
|
|
2265
|
+
} else {
|
|
2266
|
+
where.push(
|
|
2267
|
+
"(status_code IS NULL OR status_code = 0 OR status_code = 209002)",
|
|
2268
|
+
);
|
|
2269
|
+
}
|
|
2270
|
+
if (requireVideo) {
|
|
2271
|
+
where.push("COALESCE(video_count, 0) > 0");
|
|
2272
|
+
}
|
|
2273
|
+
applyLocationGroup(where, args, group);
|
|
2274
|
+
for (const filter of filters) {
|
|
2275
|
+
where.push(filter);
|
|
2276
|
+
}
|
|
2277
|
+
const sql = `
|
|
2278
|
+
SELECT *
|
|
2279
|
+
FROM jobs
|
|
2280
|
+
WHERE ${where.join(" AND ")}
|
|
2281
|
+
ORDER BY follower_count DESC, created_at ASC, unique_id ASC
|
|
2282
|
+
LIMIT 1
|
|
2283
|
+
`;
|
|
2284
|
+
const row = db.prepare(sql).get(...args);
|
|
2285
|
+
return { row, sql, args };
|
|
2094
2286
|
}
|
|
2095
2287
|
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
(
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2288
|
+
function queryPendingByGroup({ requireVideo, group, filters = [] }) {
|
|
2289
|
+
if (group?.type === "include" && group.values.length > 1) {
|
|
2290
|
+
for (const location of group.values) {
|
|
2291
|
+
const ret = queryPendingOne({
|
|
2292
|
+
requireVideo,
|
|
2293
|
+
group: { type: "include", values: [location] },
|
|
2294
|
+
filters,
|
|
2295
|
+
});
|
|
2296
|
+
if (ret.row) return ret;
|
|
2297
|
+
}
|
|
2298
|
+
return { row: null, sql: null, args: [] };
|
|
2299
|
+
}
|
|
2300
|
+
return queryPendingOne({ requireVideo, group, filters });
|
|
2104
2301
|
}
|
|
2105
2302
|
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2303
|
+
function findPinnedPending(requireVideo) {
|
|
2304
|
+
const where = ["status = 'pending'", "COALESCE(pinned, 0) = 1"];
|
|
2305
|
+
const args = [];
|
|
2306
|
+
if (!loggedIn) {
|
|
2307
|
+
where.push("COALESCE(tt_seller, 0) != 1");
|
|
2308
|
+
}
|
|
2309
|
+
if (requireVideo) {
|
|
2310
|
+
where.push("COALESCE(video_count, 0) > 0");
|
|
2311
|
+
}
|
|
2312
|
+
if (normalizedLocations.length > 0) {
|
|
2313
|
+
where.push(
|
|
2314
|
+
`UPPER(COALESCE(guessed_location, '')) IN (${normalizedLocations.map(() => "?").join(", ")})`,
|
|
2315
|
+
);
|
|
2316
|
+
args.push(...normalizedLocations);
|
|
2317
|
+
}
|
|
2318
|
+
const sql = `
|
|
2319
|
+
SELECT *
|
|
2320
|
+
FROM jobs
|
|
2321
|
+
WHERE ${where.join(" AND ")}
|
|
2322
|
+
ORDER BY created_at ASC, unique_id ASC
|
|
2323
|
+
LIMIT 1
|
|
2324
|
+
`;
|
|
2325
|
+
const row = db.prepare(sql).get(...args);
|
|
2326
|
+
return { row, sql, args };
|
|
2109
2327
|
}
|
|
2110
2328
|
|
|
2111
|
-
|
|
2112
|
-
|
|
2329
|
+
const expiredSql = `
|
|
2330
|
+
SELECT *
|
|
2331
|
+
FROM jobs
|
|
2332
|
+
WHERE status = 'processing'
|
|
2333
|
+
AND claimed_at IS NOT NULL
|
|
2334
|
+
AND ? - claimed_at > ?
|
|
2335
|
+
ORDER BY claimed_at ASC
|
|
2336
|
+
LIMIT 1
|
|
2337
|
+
`;
|
|
2338
|
+
const expiredRow = db.prepare(expiredSql).get(now, expireMs);
|
|
2339
|
+
info.expired = expiredRow
|
|
2340
|
+
? {
|
|
2341
|
+
uniqueId: expiredRow.unique_id,
|
|
2342
|
+
claimedBy: expiredRow.claimed_by,
|
|
2343
|
+
claimedAt: expiredRow.claimed_at,
|
|
2344
|
+
diffMs: now - expiredRow.claimed_at,
|
|
2345
|
+
}
|
|
2346
|
+
: null;
|
|
2113
2347
|
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
const next = pickCandidate(hasVideo) || pickCandidate(pending);
|
|
2348
|
+
info.requireVideoPasses = [];
|
|
2349
|
+
for (const requireVideo of [true, false]) {
|
|
2350
|
+
const pass = { requireVideo };
|
|
2351
|
+
const pinned = findPinnedPending(requireVideo);
|
|
2352
|
+
pass.pinned = pinned.row
|
|
2353
|
+
? {
|
|
2354
|
+
uniqueId: pinned.row.unique_id,
|
|
2355
|
+
sql: pinned.sql,
|
|
2356
|
+
args: pinned.args,
|
|
2357
|
+
}
|
|
2358
|
+
: null;
|
|
2126
2359
|
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2360
|
+
if (!pass.pinned) {
|
|
2361
|
+
for (const group of locationGroups) {
|
|
2362
|
+
const seed = queryPendingByGroup({
|
|
2363
|
+
requireVideo,
|
|
2364
|
+
group,
|
|
2365
|
+
filters: [
|
|
2366
|
+
"COALESCE(pinned, 0) = 0",
|
|
2367
|
+
`instr(COALESCE(sources, ''), '"seed"') > 0`,
|
|
2368
|
+
],
|
|
2369
|
+
});
|
|
2370
|
+
if (seed.row) {
|
|
2371
|
+
pass.seed = {
|
|
2372
|
+
uniqueId: seed.row.unique_id,
|
|
2373
|
+
group,
|
|
2374
|
+
sql: seed.sql,
|
|
2375
|
+
args: seed.args,
|
|
2376
|
+
};
|
|
2377
|
+
break;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
if (!pass.pinned && !pass.seed && loggedIn) {
|
|
2383
|
+
for (const group of locationGroups) {
|
|
2384
|
+
const seller = queryPendingByGroup({
|
|
2385
|
+
requireVideo,
|
|
2386
|
+
group,
|
|
2387
|
+
filters: [
|
|
2388
|
+
"COALESCE(pinned, 0) = 0",
|
|
2389
|
+
"tt_seller = 1",
|
|
2390
|
+
"verified = 0",
|
|
2391
|
+
],
|
|
2392
|
+
});
|
|
2393
|
+
if (seller.row) {
|
|
2394
|
+
pass.seller = {
|
|
2395
|
+
uniqueId: seller.row.unique_id,
|
|
2396
|
+
group,
|
|
2397
|
+
sql: seller.sql,
|
|
2398
|
+
args: seller.args,
|
|
2399
|
+
};
|
|
2400
|
+
break;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
if (!pass.pinned && !pass.seed && !pass.seller) {
|
|
2406
|
+
for (const group of locationGroups) {
|
|
2407
|
+
const follow = queryPendingByGroup({
|
|
2408
|
+
requireVideo,
|
|
2409
|
+
group,
|
|
2410
|
+
filters: [
|
|
2411
|
+
"COALESCE(pinned, 0) = 0",
|
|
2412
|
+
`(
|
|
2413
|
+
instr(COALESCE(sources, ''), '"following"') > 0
|
|
2414
|
+
OR instr(COALESCE(sources, ''), '"follower"') > 0
|
|
2415
|
+
)`,
|
|
2416
|
+
],
|
|
2417
|
+
});
|
|
2418
|
+
if (follow.row) {
|
|
2419
|
+
pass.follow = {
|
|
2420
|
+
uniqueId: follow.row.unique_id,
|
|
2421
|
+
group,
|
|
2422
|
+
sql: follow.sql,
|
|
2423
|
+
args: follow.args,
|
|
2424
|
+
};
|
|
2425
|
+
break;
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
if (!pass.pinned && !pass.seed && !pass.seller && !pass.follow) {
|
|
2431
|
+
for (const group of locationGroups) {
|
|
2432
|
+
const other = queryPendingByGroup({
|
|
2433
|
+
requireVideo,
|
|
2434
|
+
group,
|
|
2435
|
+
filters: ["COALESCE(pinned, 0) = 0"],
|
|
2436
|
+
});
|
|
2437
|
+
if (other.row) {
|
|
2438
|
+
pass.other = {
|
|
2439
|
+
uniqueId: other.row.unique_id,
|
|
2440
|
+
group,
|
|
2441
|
+
sql: other.sql,
|
|
2442
|
+
args: other.args,
|
|
2443
|
+
};
|
|
2444
|
+
break;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
info.requireVideoPasses.push(pass);
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
return info;
|
|
2139
2453
|
}
|
|
2140
|
-
|
|
2454
|
+
|
|
2455
|
+
return {
|
|
2456
|
+
path: "memory",
|
|
2457
|
+
userId,
|
|
2458
|
+
expireMs,
|
|
2459
|
+
loggedIn,
|
|
2460
|
+
totalUsers: data.length,
|
|
2461
|
+
processingUsers: data.filter((u) => u.status === "processing").length,
|
|
2462
|
+
pendingUsers: data.filter((u) => u.status === "pending").length,
|
|
2463
|
+
};
|
|
2141
2464
|
}
|
|
2142
2465
|
|
|
2143
2466
|
function processDiscoveredUsers(result) {
|
|
@@ -2246,6 +2569,7 @@ export function createStore(filePath) {
|
|
|
2246
2569
|
}
|
|
2247
2570
|
}
|
|
2248
2571
|
}
|
|
2572
|
+
user.restricted = true;
|
|
2249
2573
|
user.processed = true;
|
|
2250
2574
|
user.processedAt = Date.now();
|
|
2251
2575
|
user.sources = [...new Set([...(user.sources || []), "restricted"])];
|
|
@@ -3024,7 +3348,9 @@ export function createStore(filePath) {
|
|
|
3024
3348
|
getVideoCount,
|
|
3025
3349
|
getPendingCommentTasks,
|
|
3026
3350
|
commitCommentTask,
|
|
3351
|
+
debugClaimNextJob,
|
|
3027
3352
|
stopBackup,
|
|
3353
|
+
rawQuery,
|
|
3028
3354
|
data,
|
|
3029
3355
|
};
|
|
3030
3356
|
}
|