feat: 更新CC码监管方案业务版文档,新增摘要、UGC专项、直播专项、存量处置、误判申诉、水印嵌入、CC码生命周期、组织保障等章节;同步macode到cccode重命名及其他代码变更

This commit is contained in:
freedakgmail
2026-07-20 22:25:40 +08:00
parent 9f1e2d0a21
commit eb4a82a877
76 changed files with 2600 additions and 2122 deletions
+25 -25
View File
@@ -14,16 +14,16 @@ import (
// 将 MA+哈希机制从 IPTV 扩展至 OTT、手机 APP,实现大小屏内容身份互通。
// 对应任务:C.1 跨域解析网关、C.2 身份互通、B.2 扫码验真、D.1 跨屏权益子链。
// maCodePattern 匹配六段式 MA 码(含可选集级子标识 #Exx)。
// ccCodePattern 匹配六段式 MA 码(含可选集级子标识 #Exx)。
// 形如 MA.156.8531.6101/WD/20260000004 或 MA.156.8531.6101/WD/20260000004#E07
var maCodePattern = regexp.MustCompile(
var ccCodePattern = regexp.MustCompile(
`^(MA)\.(\d{3})\.([0-9A-Za-z]+)\.([0-9A-Za-z]+)/([0-9A-Za-z]+)/(\d{4})(\d+)(?:#E(\d+))?$`)
// ParseMACode 解析六段式 MA 码(纯结构解析,不查链)。
// ParseCCCode 解析六段式 MA 码(纯结构解析,不查链)。
// 返回 Valid=false 表示结构不合法(可能是伪造/损坏的码)。
func ParseMACode(maCode string) model.ParsedMA {
p := model.ParsedMA{Raw: maCode}
m := maCodePattern.FindStringSubmatch(strings.TrimSpace(maCode))
func ParseCCCode(ccCode string) model.ParsedMA {
p := model.ParsedMA{Raw: ccCode}
m := ccCodePattern.FindStringSubmatch(strings.TrimSpace(ccCode))
if m == nil {
p.Valid = false
return p
@@ -44,19 +44,19 @@ func ParseMACode(maCode string) model.ParsedMA {
return p
}
// baseMACode 去除集级子标识 #Exx,返回整剧 MA 码(用于查链/查权益)。
func baseMACode(maCode string) string {
if i := strings.Index(maCode, "#"); i >= 0 {
return maCode[:i]
// baseCCCode 去除集级子标识 #Exx,返回整剧 MA 码(用于查链/查权益)。
func baseCCCode(ccCode string) string {
if i := strings.Index(ccCode, "#"); i >= 0 {
return ccCode[:i]
}
return maCode
return ccCode
}
// Resolve 跨域解析网关(C.1/C.2):同一 MA 码在 IPTV/OTT/APP 统一解析。
// 返回解析结构 + 流通状态 + 跨屏可用性,保证大小屏解析结果一致。
func (s *Service) Resolve(maCode string) model.ResolveResult {
res := model.ResolveResult{MACode: maCode}
parsed := ParseMACode(maCode)
func (s *Service) Resolve(ccCode string) model.ResolveResult {
res := model.ResolveResult{CCCode: ccCode}
parsed := ParseCCCode(ccCode)
res.Parsed = parsed
if !parsed.Valid {
res.Resolved = false
@@ -64,7 +64,7 @@ func (s *Service) Resolve(maCode string) model.ResolveResult {
return res
}
c, err := s.chain.QueryContent(baseMACode(maCode))
c, err := s.chain.QueryContent(baseCCCode(ccCode))
if err != nil {
res.Resolved = false
res.Message = "MA 码未在可信数据空间登记"
@@ -89,9 +89,9 @@ func (s *Service) Resolve(maCode string) model.ResolveResult {
}
// ScanVerify 用户扫码验真(B.2):验证内容 MA 码真伪、合规与流通状态,防盗版。
func (s *Service) ScanVerify(maCode string) model.ScanVerifyResult {
res := model.ScanVerifyResult{MACode: maCode}
parsed := ParseMACode(maCode)
func (s *Service) ScanVerify(ccCode string) model.ScanVerifyResult {
res := model.ScanVerifyResult{CCCode: ccCode}
parsed := ParseCCCode(ccCode)
res.Parsed = parsed
if !parsed.Valid {
res.Authentic = false
@@ -100,7 +100,7 @@ func (s *Service) ScanVerify(maCode string) model.ScanVerifyResult {
return res
}
c, err := s.chain.QueryContent(baseMACode(maCode))
c, err := s.chain.QueryContent(baseCCCode(ccCode))
if err != nil {
res.Authentic = false
res.Compliant = false
@@ -127,14 +127,14 @@ func (s *Service) ScanVerify(maCode string) model.ScanVerifyResult {
// RecordPurchase 记录用户购买(D.1):用户在某一屏购买内容,记录跨屏权益。
// 校验 MA 码有效、屏类型合法;同一用户对同一 MA 码重复购买不覆盖首次记录。
func (s *Service) RecordPurchase(maCode, userHash string, screen model.ScreenType) (model.PurchaseRecord, error) {
func (s *Service) RecordPurchase(ccCode, userHash string, screen model.ScreenType) (model.PurchaseRecord, error) {
if userHash == "" {
return model.PurchaseRecord{}, fmt.Errorf("service: 缺少用户标识")
}
if !model.ValidScreen(screen) {
return model.PurchaseRecord{}, fmt.Errorf("service: 非法屏类型 %q(仅 iptv/ott/app", screen)
}
base := baseMACode(maCode)
base := baseCCCode(ccCode)
if _, err := s.chain.QueryContent(base); err != nil {
return model.PurchaseRecord{}, fmt.Errorf("service: MA 码无效或未登记: %w", err)
}
@@ -151,17 +151,17 @@ func (s *Service) RecordPurchase(maCode, userHash string, screen model.ScreenTyp
return rec, nil
}
rec := model.PurchaseRecord{
MACode: base, UserHash: userHash, Screen: screen, PurchasedAt: time.Now(),
CCCode: base, UserHash: userHash, Screen: screen, PurchasedAt: time.Now(),
}
acct.Purchases[base] = rec
return rec, nil
}
// VerifyCrossScreenRights 跨屏权益核验(D.1):任一屏购买即全屏通看,不重复付费。
func (s *Service) VerifyCrossScreenRights(maCode, userHash string, requestScreen model.ScreenType) model.CrossScreenRightsResult {
base := baseMACode(maCode)
func (s *Service) VerifyCrossScreenRights(ccCode, userHash string, requestScreen model.ScreenType) model.CrossScreenRightsResult {
base := baseCCCode(ccCode)
res := model.CrossScreenRightsResult{
MACode: base, UserHash: userHash, RequestScreen: requestScreen,
CCCode: base, UserHash: userHash, RequestScreen: requestScreen,
}
if !model.ValidScreen(requestScreen) {
res.Entitled = false