|
@@ -265,6 +265,16 @@ export class WorkService {
|
|
|
const legacyFallbackId = `${platform}_${titleForId}_${publishTimeForId}`.substring(0, 100);
|
|
const legacyFallbackId = `${platform}_${titleForId}_${publishTimeForId}`.substring(0, 100);
|
|
|
let canonicalVideoId = (workItem.videoId || '').trim() || legacyFallbackId;
|
|
let canonicalVideoId = (workItem.videoId || '').trim() || legacyFallbackId;
|
|
|
|
|
|
|
|
|
|
+ // 小红书每日同步只同步三个月内的作品(原为一年内,现改为三个月)
|
|
|
|
|
+ if (platform === 'xiaohongshu') {
|
|
|
|
|
+ const publishedAt = this.parsePublishTime(workItem.publishTime);
|
|
|
|
|
+ if (publishedAt) {
|
|
|
|
|
+ const threeMonthsAgo = new Date();
|
|
|
|
|
+ threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
|
|
|
|
|
+ if (publishedAt < threeMonthsAgo) continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (platform === 'weixin_video') {
|
|
if (platform === 'weixin_video') {
|
|
|
const rawVideoId = (workItem.videoId || '').trim();
|
|
const rawVideoId = (workItem.videoId || '').trim();
|
|
|
if (rawVideoId) {
|
|
if (rawVideoId) {
|
|
@@ -409,6 +419,10 @@ export class WorkService {
|
|
|
logger.info(`[SyncAccountWorks] Skipping local deletions for ${platform} account ${account.id} to avoid false deletions`);
|
|
logger.info(`[SyncAccountWorks] Skipping local deletions for ${platform} account ${account.id} to avoid false deletions`);
|
|
|
skipLocalDeletions = true;
|
|
skipLocalDeletions = true;
|
|
|
}
|
|
}
|
|
|
|
|
+ if (platform === 'xiaohongshu') {
|
|
|
|
|
+ logger.info(`[SyncAccountWorks] Skipping local deletions for ${platform} account ${account.id} (only syncing works within 3 months)`);
|
|
|
|
|
+ skipLocalDeletions = true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
const matchedCount = localWorks.reduce(
|
|
const matchedCount = localWorks.reduce(
|
|
|
(sum, w) => sum + (remotePlatformVideoIds.has(w.platformVideoId) ? 1 : 0),
|
|
(sum, w) => sum + (remotePlatformVideoIds.has(w.platformVideoId) ? 1 : 0),
|
|
@@ -528,6 +542,46 @@ export class WorkService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 百家号:如果是新作品且 work_day_statistics 中尚无任何记录,则异步补齐历史日统计 & works.yesterday_*(使用 BaijiahaoWorkDailyStatisticsImportService)
|
|
|
|
|
+ if (platform === 'baijiahao') {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const works = await this.workRepository.find({
|
|
|
|
|
+ where: { accountId: account.id, platform },
|
|
|
|
|
+ select: ['id'],
|
|
|
|
|
+ });
|
|
|
|
|
+ const workIds = works.map((w) => w.id);
|
|
|
|
|
+ if (workIds.length > 0) {
|
|
|
|
|
+ const rows = await AppDataSource.getRepository(WorkDayStatistics)
|
|
|
|
|
+ .createQueryBuilder('wds')
|
|
|
|
|
+ .select('DISTINCT wds.work_id', 'workId')
|
|
|
|
|
+ .where('wds.work_id IN (:...ids)', { ids: workIds })
|
|
|
|
|
+ .getRawMany();
|
|
|
|
|
+ const hasStats = new Set<number>(rows.map((r: any) => Number(r.workId)));
|
|
|
|
|
+ const needInitIds = workIds.filter((id) => !hasStats.has(id));
|
|
|
|
|
+
|
|
|
|
|
+ if (needInitIds.length > 0) {
|
|
|
|
|
+ logger.info(
|
|
|
|
|
+ `[SyncAccountWorks] BJ account ${account.id} has ${needInitIds.length} works without statistics, enqueue bj_work_stats_backfill task.`
|
|
|
|
|
+ );
|
|
|
|
|
+ taskQueueService.createTask(account.userId, {
|
|
|
|
|
+ type: 'bj_work_stats_backfill',
|
|
|
|
|
+ title: `百家号作品补数(${needInitIds.length})`,
|
|
|
|
|
+ accountId: account.id,
|
|
|
|
|
+ platform: 'baijiahao',
|
|
|
|
|
+ data: {
|
|
|
|
|
+ workIds: needInitIds,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ logger.error(
|
|
|
|
|
+ `[SyncAccountWorks] Failed to enqueue BJ work_day_statistics backfill for account ${account.id}:`,
|
|
|
|
|
+ err
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return {
|
|
return {
|
|
|
syncedCount,
|
|
syncedCount,
|
|
|
worksListLength: accountInfo.worksList?.length || 0,
|
|
worksListLength: accountInfo.worksList?.length || 0,
|