- 移除小红书:internal/platform/xiaohongshu、controlplane XHS 分支与路由、 browser_gateway XHS 平台模块与处理器、前端平台选项;migration 038 清理 XHS 数据并将 creator_* 平台 CHECK 收紧为 douyin - creator_competitor 新增 follower_count/following_count/aweme_count(仅 接口定义返回,暂不采集回填);列表接口返回 work_count 与 latest_published_at(creator_work_source 聚合 MAX(published_at)) - 导入页账号名称列展示作者头像(share job 列表带出 avatar_url) - 监控账号页改 antd Listy 卡片列表(头像+粉丝/关注/作品/最近发布/同步状态); AccountManagementList 收敛为 owned 专用 - 环境模块清理 browser_version 遗留:migration 034 补齐删列,修复 store.go 中 hub 别名悬空引用,测试 fixture 对齐新 schema
70 lines
2.7 KiB
Go
70 lines
2.7 KiB
Go
package api
|
|
|
|
// 平台收敛为抖音:collector 装配与平台身份核验 helper。
|
|
// 原小红书平台分支已随平台下线整体移除。
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.ipao.vip/rogee/creator-hub/internal/creator"
|
|
hub "git.ipao.vip/rogee/creator-hub/internal/environment"
|
|
douyin "git.ipao.vip/rogee/creator-hub/internal/platform/douyin"
|
|
)
|
|
|
|
func newCreatorCollector(ctx context.Context, platform string, gateway hub.Gateway, environment hub.EnvironmentContext, viewerAccountKey, targetAccountKey, _, sourceType, sourceID string) (creator.PlatformCollector, string, error) {
|
|
if strings.TrimSpace(viewerAccountKey) == "" || strings.TrimSpace(targetAccountKey) == "" {
|
|
return nil, "", fmt.Errorf("%w: creator collector account key is missing", creator.ErrInvalid)
|
|
}
|
|
if platform != creator.PlatformDouyin {
|
|
return nil, "", fmt.Errorf("%w: unsupported creator platform %s", creator.ErrUnavailable, platform)
|
|
}
|
|
browser := creatorGatewayBrowser{gateway: gateway, environment: environment}
|
|
if _, err := browser.Identity(ctx, viewerAccountKey); err != nil {
|
|
return nil, "", err
|
|
}
|
|
collector := douyinCollector(browser, targetAccountKey, sourceType, sourceID)
|
|
canonicalKey, err := collector.CanonicalTargetSecUID(ctx, targetAccountKey)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
return &collector, canonicalKey, nil
|
|
}
|
|
|
|
func douyinCollector(browser creatorGatewayBrowser, accountKey, sourceType, sourceID string) douyin.CreatorCollector {
|
|
return douyin.CreatorCollector{Browser: browser, AccountKey: accountKey, SourceType: sourceType, SourceID: sourceID}
|
|
}
|
|
|
|
// validateDouyinCompetitor 监控账号入队前的平台一致性校验(平台收敛后仅抖音)。
|
|
func validateDouyinCompetitor(input creator.CompetitorInput) error {
|
|
if input.Platform != creator.PlatformDouyin {
|
|
return creator.ErrInvalid
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func verifyCreatorPlatformIdentity(ctx context.Context, platform string, gateway hub.Gateway, environment hub.EnvironmentContext, expectedKey string) (string, error) {
|
|
if platform != creator.PlatformDouyin {
|
|
return "", fmt.Errorf("%w: unsupported creator platform %s", creator.ErrUnavailable, platform)
|
|
}
|
|
return (creatorGatewayBrowser{gateway: gateway, environment: environment}).Identity(ctx, expectedKey)
|
|
}
|
|
|
|
func decodeBase64(value string) ([]byte, error) {
|
|
const maxEncoded = 96 << 20
|
|
if len(value) > maxEncoded {
|
|
return nil, errors.New("media response is too large")
|
|
}
|
|
data, err := base64.StdEncoding.DecodeString(value)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode media response: %w", err)
|
|
}
|
|
if len(data) > maxCreatorMediaBytes {
|
|
return nil, errors.New("media response is too large")
|
|
}
|
|
return data, nil
|
|
}
|