批量导出Excel表格以及压缩图片

This commit is contained in:
戴育兵 2026-01-16 10:45:27 +08:00
commit 60c8855993
10 changed files with 1394 additions and 395 deletions

View File

@ -3327,6 +3327,9 @@ type WorkInfoResp struct {
ArtistPhone string `protobuf:"bytes,4,opt,name=artistPhone,proto3" json:"artistPhone"` ArtistPhone string `protobuf:"bytes,4,opt,name=artistPhone,proto3" json:"artistPhone"`
ArtistPhoneAreaCode string `protobuf:"bytes,5,opt,name=artistPhoneAreaCode,proto3" json:"artistPhoneAreaCode"` ArtistPhoneAreaCode string `protobuf:"bytes,5,opt,name=artistPhoneAreaCode,proto3" json:"artistPhoneAreaCode"`
WorkCategory uint32 `protobuf:"varint,6,opt,name=workCategory,proto3" json:"workCategory"` WorkCategory uint32 `protobuf:"varint,6,opt,name=workCategory,proto3" json:"workCategory"`
PlatformInfoData []*PlatformInfo `protobuf:"bytes,7,rep,name=platformInfoData,proto3" json:"platformInfoData"`
Title string `protobuf:"bytes,8,opt,name=title,proto3" json:"title"`
PublishStatus PublishStatusENUM `protobuf:"varint,9,opt,name=publishStatus,proto3,enum=Cast.PublishStatusENUM" json:"publishStatus"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -3403,6 +3406,27 @@ func (x *WorkInfoResp) GetWorkCategory() uint32 {
return 0 return 0
} }
func (x *WorkInfoResp) GetPlatformInfoData() []*PlatformInfo {
if x != nil {
return x.PlatformInfoData
}
return nil
}
func (x *WorkInfoResp) GetTitle() string {
if x != nil {
return x.Title
}
return ""
}
func (x *WorkInfoResp) GetPublishStatus() PublishStatusENUM {
if x != nil {
return x.PublishStatus
}
return PublishStatusENUM_PublishMediaStatus_NO
}
// 发布成功的作品列表请求 // 发布成功的作品列表请求
type WorkListPublishedReq struct { type WorkListPublishedReq struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@ -3765,7 +3789,7 @@ type PlatformInfo struct {
PublishType uint32 `protobuf:"varint,4,opt,name=publishType,proto3" json:"publishType"` PublishType uint32 `protobuf:"varint,4,opt,name=publishType,proto3" json:"publishType"`
PublishResp string `protobuf:"bytes,5,opt,name=publishResp,proto3" json:"publishResp"` PublishResp string `protobuf:"bytes,5,opt,name=publishResp,proto3" json:"publishResp"`
PublishMediaId string `protobuf:"bytes,6,opt,name=publishMediaId,proto3" json:"publishMediaId"` PublishMediaId string `protobuf:"bytes,6,opt,name=publishMediaId,proto3" json:"publishMediaId"`
PublishStatus PublishStatusENUM `protobuf:"varint,7,opt,name=publishStatus,proto3,enum=Cast.PublishStatusENUM" json:"publishStatus"` PublishMediaStatus PublishStatusENUM `protobuf:"varint,7,opt,name=publishMediaStatus,proto3,enum=Cast.PublishStatusENUM" json:"publishMediaStatus"`
Remark string `protobuf:"bytes,8,opt,name=remark,proto3" json:"remark"` Remark string `protobuf:"bytes,8,opt,name=remark,proto3" json:"remark"`
PlatformUuid string `protobuf:"bytes,9,opt,name=platformUuid,proto3" json:"platformUuid"` PlatformUuid string `protobuf:"bytes,9,opt,name=platformUuid,proto3" json:"platformUuid"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
@ -3844,9 +3868,9 @@ func (x *PlatformInfo) GetPublishMediaId() string {
return "" return ""
} }
func (x *PlatformInfo) GetPublishStatus() PublishStatusENUM { func (x *PlatformInfo) GetPublishMediaStatus() PublishStatusENUM {
if x != nil { if x != nil {
return x.PublishStatus return x.PublishMediaStatus
} }
return PublishStatusENUM_PublishMediaStatus_NO return PublishStatusENUM_PublishMediaStatus_NO
} }
@ -12947,6 +12971,7 @@ type UpsertTaskListReq struct {
Status uint32 `protobuf:"varint,4,opt,name=status,proto3" json:"status"` // 状态1-待处理 2-处理中 3-处理完成 Status uint32 `protobuf:"varint,4,opt,name=status,proto3" json:"status"` // 状态1-待处理 2-处理中 3-处理完成
OperatorID string `protobuf:"bytes,5,opt,name=operatorID,proto3" json:"operatorID"` // 操作人ID OperatorID string `protobuf:"bytes,5,opt,name=operatorID,proto3" json:"operatorID"` // 操作人ID
OperatorName string `protobuf:"bytes,6,opt,name=operatorName,proto3" json:"operatorName"` // 操作人名称 OperatorName string `protobuf:"bytes,6,opt,name=operatorName,proto3" json:"operatorName"` // 操作人名称
ExtraData string `protobuf:"bytes,7,opt,name=extraData,proto3" json:"extraData"` // 扩展信息
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -13023,6 +13048,13 @@ func (x *UpsertTaskListReq) GetOperatorName() string {
return "" return ""
} }
func (x *UpsertTaskListReq) GetExtraData() string {
if x != nil {
return x.ExtraData
}
return ""
}
// 新增或更新任务响应 // 新增或更新任务响应
type UpsertTaskListResp struct { type UpsertTaskListResp struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@ -13132,6 +13164,7 @@ type TaskListInfo struct {
OperatorName string `protobuf:"bytes,6,opt,name=operatorName,proto3" json:"operatorName"` // 操作人名称 OperatorName string `protobuf:"bytes,6,opt,name=operatorName,proto3" json:"operatorName"` // 操作人名称
CreatedAt string `protobuf:"bytes,7,opt,name=createdAt,proto3" json:"createdAt"` // 创建时间 CreatedAt string `protobuf:"bytes,7,opt,name=createdAt,proto3" json:"createdAt"` // 创建时间
UpdatedAt string `protobuf:"bytes,8,opt,name=updatedAt,proto3" json:"updatedAt"` // 更新时间 UpdatedAt string `protobuf:"bytes,8,opt,name=updatedAt,proto3" json:"updatedAt"` // 更新时间
ExtraData string `protobuf:"bytes,9,opt,name=extraData,proto3" json:"extraData"` // 扩展信息
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -13222,6 +13255,13 @@ func (x *TaskListInfo) GetUpdatedAt() string {
return "" return ""
} }
func (x *TaskListInfo) GetExtraData() string {
if x != nil {
return x.ExtraData
}
return ""
}
// 获取任务详情响应 // 获取任务详情响应
type GetTaskListResp struct { type GetTaskListResp struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@ -17263,7 +17303,7 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"DelWorkReq\x12\x1a\n" + "DelWorkReq\x12\x1a\n" +
"\bworkUuid\x18\x01 \x01(\tR\bworkUuid\")\n" + "\bworkUuid\x18\x01 \x01(\tR\bworkUuid\")\n" +
"\vWorkInfoReq\x12\x1a\n" + "\vWorkInfoReq\x12\x1a\n" +
"\bworkUuid\x18\x01 \x01(\tR\bworkUuid\"\xe6\x01\n" + "\bworkUuid\x18\x01 \x01(\tR\bworkUuid\"\xfb\x02\n" +
"\fWorkInfoResp\x12\x1e\n" + "\fWorkInfoResp\x12\x1e\n" +
"\n" + "\n" +
"workStatus\x18\x01 \x01(\rR\n" + "workStatus\x18\x01 \x01(\rR\n" +
@ -17276,7 +17316,10 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"artistName\x12 \n" + "artistName\x12 \n" +
"\vartistPhone\x18\x04 \x01(\tR\vartistPhone\x120\n" + "\vartistPhone\x18\x04 \x01(\tR\vartistPhone\x120\n" +
"\x13artistPhoneAreaCode\x18\x05 \x01(\tR\x13artistPhoneAreaCode\x12\"\n" + "\x13artistPhoneAreaCode\x18\x05 \x01(\tR\x13artistPhoneAreaCode\x12\"\n" +
"\fworkCategory\x18\x06 \x01(\rR\fworkCategory\"f\n" + "\fworkCategory\x18\x06 \x01(\rR\fworkCategory\x12>\n" +
"\x10platformInfoData\x18\a \x03(\v2\x12.Cast.PlatformInfoR\x10platformInfoData\x12\x14\n" +
"\x05title\x18\b \x01(\tR\x05title\x12=\n" +
"\rpublishStatus\x18\t \x01(\x0e2\x17.Cast.PublishStatusENUMR\rpublishStatus\"f\n" +
"\x14WorkListPublishedReq\x12\x1e\n" + "\x14WorkListPublishedReq\x12\x1e\n" +
"\n" + "\n" +
"artistUuid\x18\x01 \x01(\tR\n" + "artistUuid\x18\x01 \x01(\tR\n" +
@ -17327,7 +17370,7 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"imageWorks\x18\x01 \x03(\v2\x18.Cast.UpdateWorkImageReqR\n" + "imageWorks\x18\x01 \x03(\v2\x18.Cast.UpdateWorkImageReqR\n" +
"imageWorks\x12\"\n" + "imageWorks\x12\"\n" +
"\fsuccessCount\x18\x02 \x01(\x05R\fsuccessCount\x12\x1c\n" + "\fsuccessCount\x18\x02 \x01(\x05R\fsuccessCount\x12\x1c\n" +
"\tfailCount\x18\x03 \x01(\x05R\tfailCount\"\xdd\x02\n" + "\tfailCount\x18\x03 \x01(\x05R\tfailCount\"\xe7\x02\n" +
"\fPlatformInfo\x12\x1a\n" + "\fPlatformInfo\x12\x1a\n" +
"\bworkUuid\x18\x01 \x01(\tR\bworkUuid\x12*\n" + "\bworkUuid\x18\x01 \x01(\tR\bworkUuid\x12*\n" +
"\x10mediaAccountUuid\x18\x02 \x01(\tR\x10mediaAccountUuid\x12\x1e\n" + "\x10mediaAccountUuid\x18\x02 \x01(\tR\x10mediaAccountUuid\x12\x1e\n" +
@ -17336,8 +17379,8 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"platformID\x12 \n" + "platformID\x12 \n" +
"\vpublishType\x18\x04 \x01(\rR\vpublishType\x12 \n" + "\vpublishType\x18\x04 \x01(\rR\vpublishType\x12 \n" +
"\vpublishResp\x18\x05 \x01(\tR\vpublishResp\x12&\n" + "\vpublishResp\x18\x05 \x01(\tR\vpublishResp\x12&\n" +
"\x0epublishMediaId\x18\x06 \x01(\tR\x0epublishMediaId\x12=\n" + "\x0epublishMediaId\x18\x06 \x01(\tR\x0epublishMediaId\x12G\n" +
"\rpublishStatus\x18\a \x01(\x0e2\x17.Cast.PublishStatusENUMR\rpublishStatus\x12\x16\n" + "\x12publishMediaStatus\x18\a \x01(\x0e2\x17.Cast.PublishStatusENUMR\x12publishMediaStatus\x12\x16\n" +
"\x06remark\x18\b \x01(\tR\x06remark\x12\"\n" + "\x06remark\x18\b \x01(\tR\x06remark\x12\"\n" +
"\fplatformUuid\x18\t \x01(\tR\fplatformUuid\"[\n" + "\fplatformUuid\x18\t \x01(\tR\fplatformUuid\"[\n" +
"\x19UpdateWorkPlatformInfoReq\x12>\n" + "\x19UpdateWorkPlatformInfoReq\x12>\n" +
@ -18421,7 +18464,7 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"\tupdatedAt\x18\x14 \x01(\x05R\tupdatedAt\"`\n" + "\tupdatedAt\x18\x14 \x01(\x05R\tupdatedAt\"`\n" +
"\x18ListWorkMetricsDailyResp\x12.\n" + "\x18ListWorkMetricsDailyResp\x12.\n" +
"\x04data\x18\x01 \x03(\v2\x1a.Cast.WorkMetricsDailyInfoR\x04data\x12\x14\n" + "\x04data\x18\x01 \x03(\v2\x1a.Cast.WorkMetricsDailyInfoR\x04data\x12\x14\n" +
"\x05count\x18\x02 \x01(\x03R\x05count\"\xad\x01\n" + "\x05count\x18\x02 \x01(\x03R\x05count\"\xcb\x01\n" +
"\x11UpsertTaskListReq\x12\x12\n" + "\x11UpsertTaskListReq\x12\x12\n" +
"\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x16\n" + "\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x16\n" +
"\x06action\x18\x02 \x01(\tR\x06action\x12\x10\n" + "\x06action\x18\x02 \x01(\tR\x06action\x12\x10\n" +
@ -18430,12 +18473,13 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"\n" + "\n" +
"operatorID\x18\x05 \x01(\tR\n" + "operatorID\x18\x05 \x01(\tR\n" +
"operatorID\x12\"\n" + "operatorID\x12\"\n" +
"\foperatorName\x18\x06 \x01(\tR\foperatorName\":\n" + "\foperatorName\x18\x06 \x01(\tR\foperatorName\x12\x1c\n" +
"\textraData\x18\a \x01(\tR\textraData\":\n" +
"\x12UpsertTaskListResp\x12\x12\n" + "\x12UpsertTaskListResp\x12\x12\n" +
"\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x10\n" + "\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x10\n" +
"\x03msg\x18\x02 \x01(\tR\x03msg\"$\n" + "\x03msg\x18\x02 \x01(\tR\x03msg\"$\n" +
"\x0eGetTaskListReq\x12\x12\n" + "\x0eGetTaskListReq\x12\x12\n" +
"\x04uuid\x18\x01 \x01(\tR\x04uuid\"\xe4\x01\n" + "\x04uuid\x18\x01 \x01(\tR\x04uuid\"\x82\x02\n" +
"\fTaskListInfo\x12\x12\n" + "\fTaskListInfo\x12\x12\n" +
"\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x16\n" + "\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x16\n" +
"\x06action\x18\x02 \x01(\tR\x06action\x12\x10\n" + "\x06action\x18\x02 \x01(\tR\x06action\x12\x10\n" +
@ -18446,7 +18490,8 @@ const file_pb_fiee_cast_proto_rawDesc = "" +
"operatorID\x12\"\n" + "operatorID\x12\"\n" +
"\foperatorName\x18\x06 \x01(\tR\foperatorName\x12\x1c\n" + "\foperatorName\x18\x06 \x01(\tR\foperatorName\x12\x1c\n" +
"\tcreatedAt\x18\a \x01(\tR\tcreatedAt\x12\x1c\n" + "\tcreatedAt\x18\a \x01(\tR\tcreatedAt\x12\x1c\n" +
"\tupdatedAt\x18\b \x01(\tR\tupdatedAt\"K\n" + "\tupdatedAt\x18\b \x01(\tR\tupdatedAt\x12\x1c\n" +
"\textraData\x18\t \x01(\tR\textraData\"K\n" +
"\x0fGetTaskListResp\x12&\n" + "\x0fGetTaskListResp\x12&\n" +
"\x04data\x18\x01 \x01(\v2\x12.Cast.TaskListInfoR\x04data\x12\x10\n" + "\x04data\x18\x01 \x01(\v2\x12.Cast.TaskListInfoR\x04data\x12\x10\n" +
"\x03msg\x18\x02 \x01(\tR\x03msg\"\x91\x01\n" + "\x03msg\x18\x02 \x01(\tR\x03msg\"\x91\x01\n" +
@ -19108,268 +19153,270 @@ var file_pb_fiee_cast_proto_depIdxs = []int32{
200, // 34: Cast.MediaAccountsResp.data:type_name -> Cast.MediaAccountsResp.Info 200, // 34: Cast.MediaAccountsResp.data:type_name -> Cast.MediaAccountsResp.Info
201, // 35: Cast.MediaWorksResp.data:type_name -> Cast.MediaWorksResp.Info 201, // 35: Cast.MediaWorksResp.data:type_name -> Cast.MediaWorksResp.Info
202, // 36: Cast.PublishResp.data:type_name -> Cast.PublishResp.Info 202, // 36: Cast.PublishResp.data:type_name -> Cast.PublishResp.Info
203, // 37: Cast.WorkListPublishedResp.data:type_name -> Cast.WorkListPublishedResp.Info 48, // 37: Cast.WorkInfoResp.platformInfoData:type_name -> Cast.PlatformInfo
16, // 38: Cast.ImportWorkBatchReq.imageWorks:type_name -> Cast.UpdateWorkImageReq 4, // 38: Cast.WorkInfoResp.publishStatus:type_name -> Cast.PublishStatusENUM
16, // 39: Cast.ImportWorkBatchResp.imageWorks:type_name -> Cast.UpdateWorkImageReq 203, // 39: Cast.WorkListPublishedResp.data:type_name -> Cast.WorkListPublishedResp.Info
4, // 40: Cast.PlatformInfo.publishStatus:type_name -> Cast.PublishStatusENUM 16, // 40: Cast.ImportWorkBatchReq.imageWorks:type_name -> Cast.UpdateWorkImageReq
48, // 41: Cast.UpdateWorkPlatformInfoReq.PlatformInfoData:type_name -> Cast.PlatformInfo 16, // 41: Cast.ImportWorkBatchResp.imageWorks:type_name -> Cast.UpdateWorkImageReq
0, // 42: Cast.UpdateWorkPublishLogReq.platformID:type_name -> Cast.PlatformIDENUM 4, // 42: Cast.PlatformInfo.publishMediaStatus:type_name -> Cast.PublishStatusENUM
204, // 43: Cast.RefreshWorkListResp.Data:type_name -> Cast.RefreshWorkListResp.Info 48, // 43: Cast.UpdateWorkPlatformInfoReq.PlatformInfoData:type_name -> Cast.PlatformInfo
0, // 44: Cast.OAuthCodeToTokenReq.platformID:type_name -> Cast.PlatformIDENUM 0, // 44: Cast.UpdateWorkPublishLogReq.platformID:type_name -> Cast.PlatformIDENUM
206, // 45: Cast.UpdateOAuthReq.Data:type_name -> Cast.UpdateOAuthReq.Info 204, // 45: Cast.RefreshWorkListResp.Data:type_name -> Cast.RefreshWorkListResp.Info
0, // 46: Cast.RefreshTokenReq.platformID:type_name -> Cast.PlatformIDENUM 0, // 46: Cast.OAuthCodeToTokenReq.platformID:type_name -> Cast.PlatformIDENUM
73, // 47: Cast.ListVideoScriptsResp.data:type_name -> Cast.VideoScriptInfo 206, // 47: Cast.UpdateOAuthReq.Data:type_name -> Cast.UpdateOAuthReq.Info
73, // 48: Cast.UpdateVideoScriptBatchReq.data:type_name -> Cast.VideoScriptInfo 0, // 48: Cast.RefreshTokenReq.platformID:type_name -> Cast.PlatformIDENUM
73, // 49: Cast.UpdateVideoScriptBatchResp.data:type_name -> Cast.VideoScriptInfo 73, // 49: Cast.ListVideoScriptsResp.data:type_name -> Cast.VideoScriptInfo
2, // 50: Cast.UpdateScriptStatusReq.workAction:type_name -> Cast.WorkActionENUM 73, // 50: Cast.UpdateVideoScriptBatchReq.data:type_name -> Cast.VideoScriptInfo
6, // 51: Cast.UpdatePromptReq.category:type_name -> Cast.CategoryENUM 73, // 51: Cast.UpdateVideoScriptBatchResp.data:type_name -> Cast.VideoScriptInfo
6, // 52: Cast.GetPromptResp.category:type_name -> Cast.CategoryENUM 2, // 52: Cast.UpdateScriptStatusReq.workAction:type_name -> Cast.WorkActionENUM
6, // 53: Cast.ListPromptsReq.category:type_name -> Cast.CategoryENUM 6, // 53: Cast.UpdatePromptReq.category:type_name -> Cast.CategoryENUM
6, // 54: Cast.PromptInfo.category:type_name -> Cast.CategoryENUM 6, // 54: Cast.GetPromptResp.category:type_name -> Cast.CategoryENUM
87, // 55: Cast.ListPromptsResp.data:type_name -> Cast.PromptInfo 6, // 55: Cast.ListPromptsReq.category:type_name -> Cast.CategoryENUM
87, // 56: Cast.UpdatePromptBatchReq.data:type_name -> Cast.PromptInfo 6, // 56: Cast.PromptInfo.category:type_name -> Cast.CategoryENUM
87, // 57: Cast.UpdatePromptBatchResp.data:type_name -> Cast.PromptInfo 87, // 57: Cast.ListPromptsResp.data:type_name -> Cast.PromptInfo
91, // 58: Cast.UpdateArtistReq.artistInfo:type_name -> Cast.ArtistInfo 87, // 58: Cast.UpdatePromptBatchReq.data:type_name -> Cast.PromptInfo
91, // 59: Cast.GetArtistResp.artistInfo:type_name -> Cast.ArtistInfo 87, // 59: Cast.UpdatePromptBatchResp.data:type_name -> Cast.PromptInfo
2, // 60: Cast.UpdateWorkAnalysisStatusReq.workAction:type_name -> Cast.WorkActionENUM 91, // 60: Cast.UpdateArtistReq.artistInfo:type_name -> Cast.ArtistInfo
101, // 61: Cast.GetWorkAnalysisResp.fansSeries:type_name -> Cast.WorkAnalysisFansSeries 91, // 61: Cast.GetArtistResp.artistInfo:type_name -> Cast.ArtistInfo
102, // 62: Cast.GetWorkAnalysisResp.viewsSeries:type_name -> Cast.WorkAnalysisViewsSeries 2, // 62: Cast.UpdateWorkAnalysisStatusReq.workAction:type_name -> Cast.WorkActionENUM
103, // 63: Cast.GetWorkAnalysisResp.likesSeries:type_name -> Cast.WorkAnalysisLikesSeries 101, // 63: Cast.GetWorkAnalysisResp.fansSeries:type_name -> Cast.WorkAnalysisFansSeries
104, // 64: Cast.GetWorkAnalysisResp.commentsSeries:type_name -> Cast.WorkAnalysisCommentsSeries 102, // 64: Cast.GetWorkAnalysisResp.viewsSeries:type_name -> Cast.WorkAnalysisViewsSeries
105, // 65: Cast.GetWorkAnalysisResp.sharesSeries:type_name -> Cast.WorkAnalysisSharesSeries 103, // 65: Cast.GetWorkAnalysisResp.likesSeries:type_name -> Cast.WorkAnalysisLikesSeries
106, // 66: Cast.GetWorkAnalysisResp.topCitiesSeries:type_name -> Cast.WorkAnalysisTopCities 104, // 66: Cast.GetWorkAnalysisResp.commentsSeries:type_name -> Cast.WorkAnalysisCommentsSeries
107, // 67: Cast.GetWorkAnalysisResp.mostActiveDaySeries:type_name -> Cast.WorkAnalysisMostActiveDay 105, // 67: Cast.GetWorkAnalysisResp.sharesSeries:type_name -> Cast.WorkAnalysisSharesSeries
108, // 68: Cast.GetWorkAnalysisResp.bestPostTimeSeries:type_name -> Cast.WorkAnalysisBestPostTime 106, // 68: Cast.GetWorkAnalysisResp.topCitiesSeries:type_name -> Cast.WorkAnalysisTopCities
100, // 69: Cast.GetWorkAnalysisDetailResp.WorkAnalysisLogData:type_name -> Cast.WorkAnalysisLogInfo 107, // 69: Cast.GetWorkAnalysisResp.mostActiveDaySeries:type_name -> Cast.WorkAnalysisMostActiveDay
101, // 70: Cast.GetWorkAnalysisDetailResp.fansSeries:type_name -> Cast.WorkAnalysisFansSeries 108, // 70: Cast.GetWorkAnalysisResp.bestPostTimeSeries:type_name -> Cast.WorkAnalysisBestPostTime
102, // 71: Cast.GetWorkAnalysisDetailResp.viewsSeries:type_name -> Cast.WorkAnalysisViewsSeries 100, // 71: Cast.GetWorkAnalysisDetailResp.WorkAnalysisLogData:type_name -> Cast.WorkAnalysisLogInfo
103, // 72: Cast.GetWorkAnalysisDetailResp.likesSeries:type_name -> Cast.WorkAnalysisLikesSeries 101, // 72: Cast.GetWorkAnalysisDetailResp.fansSeries:type_name -> Cast.WorkAnalysisFansSeries
104, // 73: Cast.GetWorkAnalysisDetailResp.commentsSeries:type_name -> Cast.WorkAnalysisCommentsSeries 102, // 73: Cast.GetWorkAnalysisDetailResp.viewsSeries:type_name -> Cast.WorkAnalysisViewsSeries
105, // 74: Cast.GetWorkAnalysisDetailResp.sharesSeries:type_name -> Cast.WorkAnalysisSharesSeries 103, // 74: Cast.GetWorkAnalysisDetailResp.likesSeries:type_name -> Cast.WorkAnalysisLikesSeries
106, // 75: Cast.GetWorkAnalysisDetailResp.topCitiesSeries:type_name -> Cast.WorkAnalysisTopCities 104, // 75: Cast.GetWorkAnalysisDetailResp.commentsSeries:type_name -> Cast.WorkAnalysisCommentsSeries
107, // 76: Cast.GetWorkAnalysisDetailResp.mostActiveDaySeries:type_name -> Cast.WorkAnalysisMostActiveDay 105, // 76: Cast.GetWorkAnalysisDetailResp.sharesSeries:type_name -> Cast.WorkAnalysisSharesSeries
108, // 77: Cast.GetWorkAnalysisDetailResp.bestPostTimeSeries:type_name -> Cast.WorkAnalysisBestPostTime 106, // 77: Cast.GetWorkAnalysisDetailResp.topCitiesSeries:type_name -> Cast.WorkAnalysisTopCities
109, // 78: Cast.GetWorkAnalysisDetailResp.extra:type_name -> Cast.WorkAnalysisExtra 107, // 78: Cast.GetWorkAnalysisDetailResp.mostActiveDaySeries:type_name -> Cast.WorkAnalysisMostActiveDay
115, // 79: Cast.ListWorkAnalysisResp.data:type_name -> Cast.WorkAnalysisInfo 108, // 79: Cast.GetWorkAnalysisDetailResp.bestPostTimeSeries:type_name -> Cast.WorkAnalysisBestPostTime
119, // 80: Cast.ArtistDataListResp.data:type_name -> Cast.ArtistDataRespItem 109, // 80: Cast.GetWorkAnalysisDetailResp.extra:type_name -> Cast.WorkAnalysisExtra
122, // 81: Cast.MediaDataListResp.data:type_name -> Cast.MediaDataListItem 115, // 81: Cast.ListWorkAnalysisResp.data:type_name -> Cast.WorkAnalysisInfo
101, // 82: Cast.ArtistMetricsSeriesResp.fansSeries:type_name -> Cast.WorkAnalysisFansSeries 119, // 82: Cast.ArtistDataListResp.data:type_name -> Cast.ArtistDataRespItem
102, // 83: Cast.ArtistMetricsSeriesResp.viewsSeries:type_name -> Cast.WorkAnalysisViewsSeries 122, // 83: Cast.MediaDataListResp.data:type_name -> Cast.MediaDataListItem
103, // 84: Cast.ArtistMetricsSeriesResp.likesSeries:type_name -> Cast.WorkAnalysisLikesSeries 101, // 84: Cast.ArtistMetricsSeriesResp.fansSeries:type_name -> Cast.WorkAnalysisFansSeries
104, // 85: Cast.ArtistMetricsSeriesResp.commentsSeries:type_name -> Cast.WorkAnalysisCommentsSeries 102, // 85: Cast.ArtistMetricsSeriesResp.viewsSeries:type_name -> Cast.WorkAnalysisViewsSeries
105, // 86: Cast.ArtistMetricsSeriesResp.sharesSeries:type_name -> Cast.WorkAnalysisSharesSeries 103, // 86: Cast.ArtistMetricsSeriesResp.likesSeries:type_name -> Cast.WorkAnalysisLikesSeries
108, // 87: Cast.ArtistMetricsSeriesResp.bestPostTime:type_name -> Cast.WorkAnalysisBestPostTime 104, // 87: Cast.ArtistMetricsSeriesResp.commentsSeries:type_name -> Cast.WorkAnalysisCommentsSeries
107, // 88: Cast.ArtistMetricsSeriesResp.mostActiveDay:type_name -> Cast.WorkAnalysisMostActiveDay 105, // 88: Cast.ArtistMetricsSeriesResp.sharesSeries:type_name -> Cast.WorkAnalysisSharesSeries
129, // 89: Cast.ArtistMetricsDailyWindowResp.fans:type_name -> Cast.SimplePoint 108, // 89: Cast.ArtistMetricsSeriesResp.bestPostTime:type_name -> Cast.WorkAnalysisBestPostTime
129, // 90: Cast.ArtistMetricsDailyWindowResp.views:type_name -> Cast.SimplePoint 107, // 90: Cast.ArtistMetricsSeriesResp.mostActiveDay:type_name -> Cast.WorkAnalysisMostActiveDay
129, // 91: Cast.ArtistMetricsDailyWindowResp.likes:type_name -> Cast.SimplePoint 129, // 91: Cast.ArtistMetricsDailyWindowResp.fans:type_name -> Cast.SimplePoint
129, // 92: Cast.ArtistMetricsDailyWindowResp.comments:type_name -> Cast.SimplePoint 129, // 92: Cast.ArtistMetricsDailyWindowResp.views:type_name -> Cast.SimplePoint
129, // 93: Cast.ArtistMetricsDailyWindowResp.shares:type_name -> Cast.SimplePoint 129, // 93: Cast.ArtistMetricsDailyWindowResp.likes:type_name -> Cast.SimplePoint
130, // 94: Cast.ArtistMetricsDailyWindowResp.bestPostTime:type_name -> Cast.BestPostTimePoint 129, // 94: Cast.ArtistMetricsDailyWindowResp.comments:type_name -> Cast.SimplePoint
131, // 95: Cast.ArtistMetricsDailyWindowResp.mostActiveDay:type_name -> Cast.MostActiveDayPoint 129, // 95: Cast.ArtistMetricsDailyWindowResp.shares:type_name -> Cast.SimplePoint
134, // 96: Cast.TobeConfirmedListResp.data:type_name -> Cast.TobeConfirmedItem 130, // 96: Cast.ArtistMetricsDailyWindowResp.bestPostTime:type_name -> Cast.BestPostTimePoint
137, // 97: Cast.UpsertMediaMetricsDailyBatchReq.data:type_name -> Cast.MediaMetricsDailyItem 131, // 97: Cast.ArtistMetricsDailyWindowResp.mostActiveDay:type_name -> Cast.MostActiveDayPoint
140, // 98: Cast.UpsertWorkMetricsDailyBatchReq.data:type_name -> Cast.WorkMetricsDailyItem 134, // 98: Cast.TobeConfirmedListResp.data:type_name -> Cast.TobeConfirmedItem
144, // 99: Cast.GetArtistAyrShareInfoResp.data:type_name -> Cast.ArtistAyrShareInfo 137, // 99: Cast.UpsertMediaMetricsDailyBatchReq.data:type_name -> Cast.MediaMetricsDailyItem
144, // 100: Cast.GetArtistAyrShareInfoByPlatformIDsResp.data:type_name -> Cast.ArtistAyrShareInfo 140, // 100: Cast.UpsertWorkMetricsDailyBatchReq.data:type_name -> Cast.WorkMetricsDailyItem
149, // 101: Cast.ListWorkPlatformInfoResp.data:type_name -> Cast.WorkPlatformInfo 144, // 101: Cast.GetArtistAyrShareInfoResp.data:type_name -> Cast.ArtistAyrShareInfo
152, // 102: Cast.ListMediaMetricsDailyResp.data:type_name -> Cast.MediaMetricsDailyInfo 144, // 102: Cast.GetArtistAyrShareInfoByPlatformIDsResp.data:type_name -> Cast.ArtistAyrShareInfo
155, // 103: Cast.ListWorkMetricsDailyResp.data:type_name -> Cast.WorkMetricsDailyInfo 149, // 103: Cast.ListWorkPlatformInfoResp.data:type_name -> Cast.WorkPlatformInfo
160, // 104: Cast.GetTaskListResp.data:type_name -> Cast.TaskListInfo 152, // 104: Cast.ListMediaMetricsDailyResp.data:type_name -> Cast.MediaMetricsDailyInfo
160, // 105: Cast.ListTaskListResp.data:type_name -> Cast.TaskListInfo 155, // 105: Cast.ListWorkMetricsDailyResp.data:type_name -> Cast.WorkMetricsDailyInfo
170, // 106: Cast.ListCastTagsResp.data:type_name -> Cast.CastTagInfo 160, // 106: Cast.GetTaskListResp.data:type_name -> Cast.TaskListInfo
170, // 107: Cast.UpdateCastTagBatchReq.data:type_name -> Cast.CastTagInfo 160, // 107: Cast.ListTaskListResp.data:type_name -> Cast.TaskListInfo
170, // 108: Cast.UpdateCastTagBatchResp.data:type_name -> Cast.CastTagInfo 170, // 108: Cast.ListCastTagsResp.data:type_name -> Cast.CastTagInfo
170, // 109: Cast.BatchUpdateCastTagsReq.data:type_name -> Cast.CastTagInfo 170, // 109: Cast.UpdateCastTagBatchReq.data:type_name -> Cast.CastTagInfo
2, // 110: Cast.UpdateCompetitiveReportStatusReq.workAction:type_name -> Cast.WorkActionENUM 170, // 110: Cast.UpdateCastTagBatchResp.data:type_name -> Cast.CastTagInfo
182, // 111: Cast.GetCompetitiveReportDetailResp.reportLogData:type_name -> Cast.CompetitiveReportLogInfo 170, // 111: Cast.BatchUpdateCastTagsReq.data:type_name -> Cast.CastTagInfo
183, // 112: Cast.GetCompetitiveReportDetailResp.extra:type_name -> Cast.CompetitiveReportExtra 2, // 112: Cast.UpdateCompetitiveReportStatusReq.workAction:type_name -> Cast.WorkActionENUM
189, // 113: Cast.ListCompetitiveReportResp.data:type_name -> Cast.CompetitiveReportInfo 182, // 113: Cast.GetCompetitiveReportDetailResp.reportLogData:type_name -> Cast.CompetitiveReportLogInfo
177, // 114: Cast.ImportCompetitiveReportBatchReq.reports:type_name -> Cast.CreateCompetitiveReportReq 183, // 114: Cast.GetCompetitiveReportDetailResp.extra:type_name -> Cast.CompetitiveReportExtra
177, // 115: Cast.ImportCompetitiveReportBatchResp.reports:type_name -> Cast.CreateCompetitiveReportReq 189, // 115: Cast.ListCompetitiveReportResp.data:type_name -> Cast.CompetitiveReportInfo
195, // 116: Cast.CountCompetitiveReportByWorkUuidsResp.data:type_name -> Cast.WorkUuidCount 177, // 116: Cast.ImportCompetitiveReportBatchReq.reports:type_name -> Cast.CreateCompetitiveReportReq
198, // 117: Cast.WorkListResp.Info.PublishMediaIDs:type_name -> Cast.WorkListResp.Info.PublishMediaIDsEntry 177, // 117: Cast.ImportCompetitiveReportBatchResp.reports:type_name -> Cast.CreateCompetitiveReportReq
9, // 118: Cast.WorkDetailResp.MediaAccDataEntry.value:type_name -> Cast.MediaUserInfo 195, // 118: Cast.CountCompetitiveReportByWorkUuidsResp.data:type_name -> Cast.WorkUuidCount
205, // 119: Cast.RefreshWorkListResp.Info.PlatformInfoData:type_name -> Cast.RefreshWorkListResp.Info.PlatformInfo 198, // 119: Cast.WorkListResp.Info.PublishMediaIDs:type_name -> Cast.WorkListResp.Info.PublishMediaIDsEntry
0, // 120: Cast.RefreshWorkListResp.Info.PlatformInfo.platformID:type_name -> Cast.PlatformIDENUM 9, // 120: Cast.WorkDetailResp.MediaAccDataEntry.value:type_name -> Cast.MediaUserInfo
0, // 121: Cast.UpdateOAuthReq.Info.platformID:type_name -> Cast.PlatformIDENUM 205, // 121: Cast.RefreshWorkListResp.Info.PlatformInfoData:type_name -> Cast.RefreshWorkListResp.Info.PlatformInfo
8, // 122: Cast.Cast.MediaUserList:input_type -> Cast.MediaUserListReq 0, // 122: Cast.RefreshWorkListResp.Info.PlatformInfo.platformID:type_name -> Cast.PlatformIDENUM
11, // 123: Cast.Cast.UpdateMediaAccount:input_type -> Cast.UpdateMediaAccountReq 0, // 123: Cast.UpdateOAuthReq.Info.platformID:type_name -> Cast.PlatformIDENUM
13, // 124: Cast.Cast.UnbindManager:input_type -> Cast.UnbindManagerReq 8, // 124: Cast.Cast.MediaUserList:input_type -> Cast.MediaUserListReq
15, // 125: Cast.Cast.BindManager:input_type -> Cast.BindManagerReq 11, // 125: Cast.Cast.UpdateMediaAccount:input_type -> Cast.UpdateMediaAccountReq
16, // 126: Cast.Cast.UpdateWorkImage:input_type -> Cast.UpdateWorkImageReq 13, // 126: Cast.Cast.UnbindManager:input_type -> Cast.UnbindManagerReq
19, // 127: Cast.Cast.UpdateWorkVideo:input_type -> Cast.UpdateWorkVideoReq 15, // 127: Cast.Cast.BindManager:input_type -> Cast.BindManagerReq
21, // 128: Cast.Cast.MediaInfo:input_type -> Cast.MediaInfoReq 16, // 128: Cast.Cast.UpdateWorkImage:input_type -> Cast.UpdateWorkImageReq
23, // 129: Cast.Cast.MediaInfoByPlatform:input_type -> Cast.MediaInfoByPlatformReq 19, // 129: Cast.Cast.UpdateWorkVideo:input_type -> Cast.UpdateWorkVideoReq
25, // 130: Cast.Cast.WorkList:input_type -> Cast.WorkListReq 21, // 130: Cast.Cast.MediaInfo:input_type -> Cast.MediaInfoReq
42, // 131: Cast.Cast.WorkListPublished:input_type -> Cast.WorkListPublishedReq 23, // 131: Cast.Cast.MediaInfoByPlatform:input_type -> Cast.MediaInfoByPlatformReq
27, // 132: Cast.Cast.WorkDetail:input_type -> Cast.WorkDetailReq 25, // 132: Cast.Cast.WorkList:input_type -> Cast.WorkListReq
30, // 133: Cast.Cast.UpdateStatus:input_type -> Cast.UpdateStatusReq 42, // 133: Cast.Cast.WorkListPublished:input_type -> Cast.WorkListPublishedReq
31, // 134: Cast.Cast.MediaAccounts:input_type -> Cast.MediaAccountsReq 27, // 134: Cast.Cast.WorkDetail:input_type -> Cast.WorkDetailReq
33, // 135: Cast.Cast.MediaWorks:input_type -> Cast.MediaWorksReq 30, // 135: Cast.Cast.UpdateStatus:input_type -> Cast.UpdateStatusReq
35, // 136: Cast.Cast.Publish:input_type -> Cast.PublishReq 31, // 136: Cast.Cast.MediaAccounts:input_type -> Cast.MediaAccountsReq
37, // 137: Cast.Cast.RePublish:input_type -> Cast.RePublishReq 33, // 137: Cast.Cast.MediaWorks:input_type -> Cast.MediaWorksReq
39, // 138: Cast.Cast.DelWork:input_type -> Cast.DelWorkReq 35, // 138: Cast.Cast.Publish:input_type -> Cast.PublishReq
40, // 139: Cast.Cast.WorkInfo:input_type -> Cast.WorkInfoReq 37, // 139: Cast.Cast.RePublish:input_type -> Cast.RePublishReq
44, // 140: Cast.Cast.ArtistInfo:input_type -> Cast.ArtistInfoReq 39, // 140: Cast.Cast.DelWork:input_type -> Cast.DelWorkReq
46, // 141: Cast.Cast.ImportWorkBatch:input_type -> Cast.ImportWorkBatchReq 40, // 141: Cast.Cast.WorkInfo:input_type -> Cast.WorkInfoReq
49, // 142: Cast.Cast.UpdateWorkPlatformInfo:input_type -> Cast.UpdateWorkPlatformInfoReq 44, // 142: Cast.Cast.ArtistInfo:input_type -> Cast.ArtistInfoReq
51, // 143: Cast.Cast.UpdateWorkPublishLog:input_type -> Cast.UpdateWorkPublishLogReq 46, // 143: Cast.Cast.ImportWorkBatch:input_type -> Cast.ImportWorkBatchReq
52, // 144: Cast.Cast.RefreshWorkList:input_type -> Cast.RefreshWorkListReq 49, // 144: Cast.Cast.UpdateWorkPlatformInfo:input_type -> Cast.UpdateWorkPlatformInfoReq
54, // 145: Cast.Cast.OAuthAccount:input_type -> Cast.OAuthAccountReq 51, // 145: Cast.Cast.UpdateWorkPublishLog:input_type -> Cast.UpdateWorkPublishLogReq
56, // 146: Cast.Cast.OAuthAccountV2:input_type -> Cast.OAuthAccountV2Req 52, // 146: Cast.Cast.RefreshWorkList:input_type -> Cast.RefreshWorkListReq
60, // 147: Cast.Cast.OAuthCodeToToken:input_type -> Cast.OAuthCodeToTokenReq 54, // 147: Cast.Cast.OAuthAccount:input_type -> Cast.OAuthAccountReq
62, // 148: Cast.Cast.UpdateOAuth:input_type -> Cast.UpdateOAuthReq 56, // 148: Cast.Cast.OAuthAccountV2:input_type -> Cast.OAuthAccountV2Req
63, // 149: Cast.Cast.RefreshToken:input_type -> Cast.RefreshTokenReq 60, // 149: Cast.Cast.OAuthCodeToToken:input_type -> Cast.OAuthCodeToTokenReq
65, // 150: Cast.Cast.PublishMediaInfo:input_type -> Cast.PublishMediaInfoReq 62, // 150: Cast.Cast.UpdateOAuth:input_type -> Cast.UpdateOAuthReq
67, // 151: Cast.Cast.Tools:input_type -> Cast.ToolsReq 63, // 151: Cast.Cast.RefreshToken:input_type -> Cast.RefreshTokenReq
68, // 152: Cast.Cast.UpdateVideoScript:input_type -> Cast.UpdateVideoScriptReq 65, // 152: Cast.Cast.PublishMediaInfo:input_type -> Cast.PublishMediaInfoReq
70, // 153: Cast.Cast.GetVideoScript:input_type -> Cast.GetVideoScriptReq 67, // 153: Cast.Cast.Tools:input_type -> Cast.ToolsReq
72, // 154: Cast.Cast.ListVideoScripts:input_type -> Cast.ListVideoScriptsReq 68, // 154: Cast.Cast.UpdateVideoScript:input_type -> Cast.UpdateVideoScriptReq
75, // 155: Cast.Cast.DeleteVideoScript:input_type -> Cast.DeleteVideoScriptReq 70, // 155: Cast.Cast.GetVideoScript:input_type -> Cast.GetVideoScriptReq
76, // 156: Cast.Cast.UpdateVideoScriptBatch:input_type -> Cast.UpdateVideoScriptBatchReq 72, // 156: Cast.Cast.ListVideoScripts:input_type -> Cast.ListVideoScriptsReq
78, // 157: Cast.Cast.UpdateScriptStatus:input_type -> Cast.UpdateScriptStatusReq 75, // 157: Cast.Cast.DeleteVideoScript:input_type -> Cast.DeleteVideoScriptReq
80, // 158: Cast.Cast.GetLayout:input_type -> Cast.GetLayoutReq 76, // 158: Cast.Cast.UpdateVideoScriptBatch:input_type -> Cast.UpdateVideoScriptBatchReq
79, // 159: Cast.Cast.SetLayout:input_type -> Cast.SetLayoutReq 78, // 159: Cast.Cast.UpdateScriptStatus:input_type -> Cast.UpdateScriptStatusReq
82, // 160: Cast.Cast.UpdatePrompt:input_type -> Cast.UpdatePromptReq 80, // 160: Cast.Cast.GetLayout:input_type -> Cast.GetLayoutReq
83, // 161: Cast.Cast.DeletePrompt:input_type -> Cast.DeletePromptReq 79, // 161: Cast.Cast.SetLayout:input_type -> Cast.SetLayoutReq
84, // 162: Cast.Cast.GetPrompt:input_type -> Cast.GetPromptReq 82, // 162: Cast.Cast.UpdatePrompt:input_type -> Cast.UpdatePromptReq
86, // 163: Cast.Cast.ListPrompts:input_type -> Cast.ListPromptsReq 83, // 163: Cast.Cast.DeletePrompt:input_type -> Cast.DeletePromptReq
89, // 164: Cast.Cast.UpdatePromptBatch:input_type -> Cast.UpdatePromptBatchReq 84, // 164: Cast.Cast.GetPrompt:input_type -> Cast.GetPromptReq
92, // 165: Cast.Cast.UpdateArtist:input_type -> Cast.UpdateArtistReq 86, // 165: Cast.Cast.ListPrompts:input_type -> Cast.ListPromptsReq
94, // 166: Cast.Cast.GetArtist:input_type -> Cast.GetArtistReq 89, // 166: Cast.Cast.UpdatePromptBatch:input_type -> Cast.UpdatePromptBatchReq
96, // 167: Cast.Cast.CreateWorkAnalysis:input_type -> Cast.CreateWorkAnalysisReq 92, // 167: Cast.Cast.UpdateArtist:input_type -> Cast.UpdateArtistReq
98, // 168: Cast.Cast.UpdateWorkAnalysis:input_type -> Cast.UpdateWorkAnalysisReq 94, // 168: Cast.Cast.GetArtist:input_type -> Cast.GetArtistReq
99, // 169: Cast.Cast.UpdateWorkAnalysisStatus:input_type -> Cast.UpdateWorkAnalysisStatusReq 96, // 169: Cast.Cast.CreateWorkAnalysis:input_type -> Cast.CreateWorkAnalysisReq
110, // 170: Cast.Cast.GetWorkAnalysis:input_type -> Cast.GetWorkAnalysisDetailReq 98, // 170: Cast.Cast.UpdateWorkAnalysis:input_type -> Cast.UpdateWorkAnalysisReq
111, // 171: Cast.Cast.GetLatestWorkAnalysis:input_type -> Cast.GetLatestWorkAnalysisReq 99, // 171: Cast.Cast.UpdateWorkAnalysisStatus:input_type -> Cast.UpdateWorkAnalysisStatusReq
114, // 172: Cast.Cast.ListWorkAnalysis:input_type -> Cast.ListWorkAnalysisReq 110, // 172: Cast.Cast.GetWorkAnalysis:input_type -> Cast.GetWorkAnalysisDetailReq
117, // 173: Cast.Cast.DeleteWorkAnalysis:input_type -> Cast.DeleteWorkAnalysisReq 111, // 173: Cast.Cast.GetLatestWorkAnalysis:input_type -> Cast.GetLatestWorkAnalysisReq
136, // 174: Cast.Cast.UpdateWorkAnalysisApprovalID:input_type -> Cast.UpdateWorkAnalysisApprovalIDReq 114, // 174: Cast.Cast.ListWorkAnalysis:input_type -> Cast.ListWorkAnalysisReq
118, // 175: Cast.Cast.ArtistDataList:input_type -> Cast.ArtistDataListReq 117, // 175: Cast.Cast.DeleteWorkAnalysis:input_type -> Cast.DeleteWorkAnalysisReq
121, // 176: Cast.Cast.MediaDataList:input_type -> Cast.MediaDataListReq 136, // 176: Cast.Cast.UpdateWorkAnalysisApprovalID:input_type -> Cast.UpdateWorkAnalysisApprovalIDReq
124, // 177: Cast.Cast.DataOverview:input_type -> Cast.DataOverviewReq 118, // 177: Cast.Cast.ArtistDataList:input_type -> Cast.ArtistDataListReq
126, // 178: Cast.Cast.ArtistMetricsSeries:input_type -> Cast.ArtistMetricsSeriesReq 121, // 178: Cast.Cast.MediaDataList:input_type -> Cast.MediaDataListReq
128, // 179: Cast.Cast.ArtistMetricsDailyWindow:input_type -> Cast.ArtistMetricsDailyWindowReq 124, // 179: Cast.Cast.DataOverview:input_type -> Cast.DataOverviewReq
133, // 180: Cast.Cast.TobeConfirmedList:input_type -> Cast.TobeConfirmedListReq 126, // 180: Cast.Cast.ArtistMetricsSeries:input_type -> Cast.ArtistMetricsSeriesReq
138, // 181: Cast.Cast.UpsertMediaMetricsDailyBatch:input_type -> Cast.UpsertMediaMetricsDailyBatchReq 128, // 181: Cast.Cast.ArtistMetricsDailyWindow:input_type -> Cast.ArtistMetricsDailyWindowReq
141, // 182: Cast.Cast.UpsertWorkMetricsDailyBatch:input_type -> Cast.UpsertWorkMetricsDailyBatchReq 133, // 182: Cast.Cast.TobeConfirmedList:input_type -> Cast.TobeConfirmedListReq
151, // 183: Cast.Cast.ListMediaMetricsDaily:input_type -> Cast.ListMediaMetricsDailyReq 138, // 183: Cast.Cast.UpsertMediaMetricsDailyBatch:input_type -> Cast.UpsertMediaMetricsDailyBatchReq
154, // 184: Cast.Cast.ListWorkMetricsDaily:input_type -> Cast.ListWorkMetricsDailyReq 141, // 184: Cast.Cast.UpsertWorkMetricsDailyBatch:input_type -> Cast.UpsertWorkMetricsDailyBatchReq
165, // 185: Cast.Cast.CalculateMediaMetricsByWorks:input_type -> Cast.CalculateMediaMetricsByWorksReq 151, // 185: Cast.Cast.ListMediaMetricsDaily:input_type -> Cast.ListMediaMetricsDailyReq
143, // 186: Cast.Cast.GetArtistAyrShareInfo:input_type -> Cast.GetArtistAyrShareInfoReq 154, // 186: Cast.Cast.ListWorkMetricsDaily:input_type -> Cast.ListWorkMetricsDailyReq
146, // 187: Cast.Cast.GetArtistAyrShareInfoByPlatformIDs:input_type -> Cast.GetArtistAyrShareInfoByPlatformIDsReq 165, // 187: Cast.Cast.CalculateMediaMetricsByWorks:input_type -> Cast.CalculateMediaMetricsByWorksReq
148, // 188: Cast.Cast.ListWorkPlatformInfo:input_type -> Cast.ListWorkPlatformInfoReq 143, // 188: Cast.Cast.GetArtistAyrShareInfo:input_type -> Cast.GetArtistAyrShareInfoReq
157, // 189: Cast.Cast.UpsertTaskList:input_type -> Cast.UpsertTaskListReq 146, // 189: Cast.Cast.GetArtistAyrShareInfoByPlatformIDs:input_type -> Cast.GetArtistAyrShareInfoByPlatformIDsReq
159, // 190: Cast.Cast.GetTaskList:input_type -> Cast.GetTaskListReq 148, // 190: Cast.Cast.ListWorkPlatformInfo:input_type -> Cast.ListWorkPlatformInfoReq
162, // 191: Cast.Cast.ListTaskList:input_type -> Cast.ListTaskListReq 157, // 191: Cast.Cast.UpsertTaskList:input_type -> Cast.UpsertTaskListReq
164, // 192: Cast.Cast.DeleteTaskList:input_type -> Cast.DeleteTaskListReq 159, // 192: Cast.Cast.GetTaskList:input_type -> Cast.GetTaskListReq
167, // 193: Cast.Cast.UpdateCastTag:input_type -> Cast.UpdateCastTagReq 162, // 193: Cast.Cast.ListTaskList:input_type -> Cast.ListTaskListReq
169, // 194: Cast.Cast.ListCastTags:input_type -> Cast.ListCastTagsReq 164, // 194: Cast.Cast.DeleteTaskList:input_type -> Cast.DeleteTaskListReq
172, // 195: Cast.Cast.UpdateCastTagBatch:input_type -> Cast.UpdateCastTagBatchReq 167, // 195: Cast.Cast.UpdateCastTag:input_type -> Cast.UpdateCastTagReq
174, // 196: Cast.Cast.BatchUpdateCastTags:input_type -> Cast.BatchUpdateCastTagsReq 169, // 196: Cast.Cast.ListCastTags:input_type -> Cast.ListCastTagsReq
175, // 197: Cast.Cast.UpdateCastTagStatus:input_type -> Cast.UpdateCastTagStatusReq 172, // 197: Cast.Cast.UpdateCastTagBatch:input_type -> Cast.UpdateCastTagBatchReq
207, // 198: Cast.Cast.RecalculateCastTagQuoteCount:input_type -> google.protobuf.Empty 174, // 198: Cast.Cast.BatchUpdateCastTags:input_type -> Cast.BatchUpdateCastTagsReq
177, // 199: Cast.Cast.CreateCompetitiveReport:input_type -> Cast.CreateCompetitiveReportReq 175, // 199: Cast.Cast.UpdateCastTagStatus:input_type -> Cast.UpdateCastTagStatusReq
192, // 200: Cast.Cast.ImportCompetitiveReportBatch:input_type -> Cast.ImportCompetitiveReportBatchReq 207, // 200: Cast.Cast.RecalculateCastTagQuoteCount:input_type -> google.protobuf.Empty
180, // 201: Cast.Cast.UpdateCompetitiveReportStatus:input_type -> Cast.UpdateCompetitiveReportStatusReq 177, // 201: Cast.Cast.CreateCompetitiveReport:input_type -> Cast.CreateCompetitiveReportReq
184, // 202: Cast.Cast.GetCompetitiveReport:input_type -> Cast.GetCompetitiveReportDetailReq 192, // 202: Cast.Cast.ImportCompetitiveReportBatch:input_type -> Cast.ImportCompetitiveReportBatchReq
185, // 203: Cast.Cast.GetCompetitiveReportForApp:input_type -> Cast.GetCompetitiveReportForAppReq 180, // 203: Cast.Cast.UpdateCompetitiveReportStatus:input_type -> Cast.UpdateCompetitiveReportStatusReq
188, // 204: Cast.Cast.ListCompetitiveReport:input_type -> Cast.ListCompetitiveReportReq 184, // 204: Cast.Cast.GetCompetitiveReport:input_type -> Cast.GetCompetitiveReportDetailReq
191, // 205: Cast.Cast.DeleteCompetitiveReport:input_type -> Cast.DeleteCompetitiveReportReq 185, // 205: Cast.Cast.GetCompetitiveReportForApp:input_type -> Cast.GetCompetitiveReportForAppReq
181, // 206: Cast.Cast.UpdateCompetitiveReportApprovalID:input_type -> Cast.UpdateCompetitiveReportApprovalIDReq 188, // 206: Cast.Cast.ListCompetitiveReport:input_type -> Cast.ListCompetitiveReportReq
194, // 207: Cast.Cast.CountCompetitiveReportByWorkUuids:input_type -> Cast.CountCompetitiveReportByWorkUuidsReq 191, // 207: Cast.Cast.DeleteCompetitiveReport:input_type -> Cast.DeleteCompetitiveReportReq
10, // 208: Cast.Cast.MediaUserList:output_type -> Cast.MediaUserListResp 181, // 208: Cast.Cast.UpdateCompetitiveReportApprovalID:input_type -> Cast.UpdateCompetitiveReportApprovalIDReq
12, // 209: Cast.Cast.UpdateMediaAccount:output_type -> Cast.UpdateMediaAccountResp 194, // 209: Cast.Cast.CountCompetitiveReportByWorkUuids:input_type -> Cast.CountCompetitiveReportByWorkUuidsReq
14, // 210: Cast.Cast.UnbindManager:output_type -> Cast.UnbindManagerResp 10, // 210: Cast.Cast.MediaUserList:output_type -> Cast.MediaUserListResp
207, // 211: Cast.Cast.BindManager:output_type -> google.protobuf.Empty 12, // 211: Cast.Cast.UpdateMediaAccount:output_type -> Cast.UpdateMediaAccountResp
17, // 212: Cast.Cast.UpdateWorkImage:output_type -> Cast.UpdateWorkImageResp 14, // 212: Cast.Cast.UnbindManager:output_type -> Cast.UnbindManagerResp
20, // 213: Cast.Cast.UpdateWorkVideo:output_type -> Cast.UpdateWorkVideoResp 207, // 213: Cast.Cast.BindManager:output_type -> google.protobuf.Empty
22, // 214: Cast.Cast.MediaInfo:output_type -> Cast.MediaInfoResp 17, // 214: Cast.Cast.UpdateWorkImage:output_type -> Cast.UpdateWorkImageResp
24, // 215: Cast.Cast.MediaInfoByPlatform:output_type -> Cast.MediaInfoByPlatformResp 20, // 215: Cast.Cast.UpdateWorkVideo:output_type -> Cast.UpdateWorkVideoResp
26, // 216: Cast.Cast.WorkList:output_type -> Cast.WorkListResp 22, // 216: Cast.Cast.MediaInfo:output_type -> Cast.MediaInfoResp
43, // 217: Cast.Cast.WorkListPublished:output_type -> Cast.WorkListPublishedResp 24, // 217: Cast.Cast.MediaInfoByPlatform:output_type -> Cast.MediaInfoByPlatformResp
29, // 218: Cast.Cast.WorkDetail:output_type -> Cast.WorkDetailResp 26, // 218: Cast.Cast.WorkList:output_type -> Cast.WorkListResp
207, // 219: Cast.Cast.UpdateStatus:output_type -> google.protobuf.Empty 43, // 219: Cast.Cast.WorkListPublished:output_type -> Cast.WorkListPublishedResp
32, // 220: Cast.Cast.MediaAccounts:output_type -> Cast.MediaAccountsResp 29, // 220: Cast.Cast.WorkDetail:output_type -> Cast.WorkDetailResp
34, // 221: Cast.Cast.MediaWorks:output_type -> Cast.MediaWorksResp 207, // 221: Cast.Cast.UpdateStatus:output_type -> google.protobuf.Empty
36, // 222: Cast.Cast.Publish:output_type -> Cast.PublishResp 32, // 222: Cast.Cast.MediaAccounts:output_type -> Cast.MediaAccountsResp
38, // 223: Cast.Cast.RePublish:output_type -> Cast.RePublishResp 34, // 223: Cast.Cast.MediaWorks:output_type -> Cast.MediaWorksResp
207, // 224: Cast.Cast.DelWork:output_type -> google.protobuf.Empty 36, // 224: Cast.Cast.Publish:output_type -> Cast.PublishResp
41, // 225: Cast.Cast.WorkInfo:output_type -> Cast.WorkInfoResp 38, // 225: Cast.Cast.RePublish:output_type -> Cast.RePublishResp
45, // 226: Cast.Cast.ArtistInfo:output_type -> Cast.ArtistInfoResp 207, // 226: Cast.Cast.DelWork:output_type -> google.protobuf.Empty
47, // 227: Cast.Cast.ImportWorkBatch:output_type -> Cast.ImportWorkBatchResp 41, // 227: Cast.Cast.WorkInfo:output_type -> Cast.WorkInfoResp
50, // 228: Cast.Cast.UpdateWorkPlatformInfo:output_type -> Cast.UpdateWorkPlatformInfoResp 45, // 228: Cast.Cast.ArtistInfo:output_type -> Cast.ArtistInfoResp
207, // 229: Cast.Cast.UpdateWorkPublishLog:output_type -> google.protobuf.Empty 47, // 229: Cast.Cast.ImportWorkBatch:output_type -> Cast.ImportWorkBatchResp
53, // 230: Cast.Cast.RefreshWorkList:output_type -> Cast.RefreshWorkListResp 50, // 230: Cast.Cast.UpdateWorkPlatformInfo:output_type -> Cast.UpdateWorkPlatformInfoResp
55, // 231: Cast.Cast.OAuthAccount:output_type -> Cast.OAuthAccountResp 207, // 231: Cast.Cast.UpdateWorkPublishLog:output_type -> google.protobuf.Empty
57, // 232: Cast.Cast.OAuthAccountV2:output_type -> Cast.OAuthAccountV2Resp 53, // 232: Cast.Cast.RefreshWorkList:output_type -> Cast.RefreshWorkListResp
61, // 233: Cast.Cast.OAuthCodeToToken:output_type -> Cast.OAuthCodeToTokenResp 55, // 233: Cast.Cast.OAuthAccount:output_type -> Cast.OAuthAccountResp
207, // 234: Cast.Cast.UpdateOAuth:output_type -> google.protobuf.Empty 57, // 234: Cast.Cast.OAuthAccountV2:output_type -> Cast.OAuthAccountV2Resp
64, // 235: Cast.Cast.RefreshToken:output_type -> Cast.RefreshTokenResp 61, // 235: Cast.Cast.OAuthCodeToToken:output_type -> Cast.OAuthCodeToTokenResp
66, // 236: Cast.Cast.PublishMediaInfo:output_type -> Cast.PublishMediaInfoResp 207, // 236: Cast.Cast.UpdateOAuth:output_type -> google.protobuf.Empty
207, // 237: Cast.Cast.Tools:output_type -> google.protobuf.Empty 64, // 237: Cast.Cast.RefreshToken:output_type -> Cast.RefreshTokenResp
69, // 238: Cast.Cast.UpdateVideoScript:output_type -> Cast.UpdateVideoScriptResp 66, // 238: Cast.Cast.PublishMediaInfo:output_type -> Cast.PublishMediaInfoResp
71, // 239: Cast.Cast.GetVideoScript:output_type -> Cast.GetVideoScriptResp 207, // 239: Cast.Cast.Tools:output_type -> google.protobuf.Empty
74, // 240: Cast.Cast.ListVideoScripts:output_type -> Cast.ListVideoScriptsResp 69, // 240: Cast.Cast.UpdateVideoScript:output_type -> Cast.UpdateVideoScriptResp
207, // 241: Cast.Cast.DeleteVideoScript:output_type -> google.protobuf.Empty 71, // 241: Cast.Cast.GetVideoScript:output_type -> Cast.GetVideoScriptResp
77, // 242: Cast.Cast.UpdateVideoScriptBatch:output_type -> Cast.UpdateVideoScriptBatchResp 74, // 242: Cast.Cast.ListVideoScripts:output_type -> Cast.ListVideoScriptsResp
207, // 243: Cast.Cast.UpdateScriptStatus:output_type -> google.protobuf.Empty 207, // 243: Cast.Cast.DeleteVideoScript:output_type -> google.protobuf.Empty
81, // 244: Cast.Cast.GetLayout:output_type -> Cast.GetLayoutResp 77, // 244: Cast.Cast.UpdateVideoScriptBatch:output_type -> Cast.UpdateVideoScriptBatchResp
207, // 245: Cast.Cast.SetLayout:output_type -> google.protobuf.Empty 207, // 245: Cast.Cast.UpdateScriptStatus:output_type -> google.protobuf.Empty
207, // 246: Cast.Cast.UpdatePrompt:output_type -> google.protobuf.Empty 81, // 246: Cast.Cast.GetLayout:output_type -> Cast.GetLayoutResp
207, // 247: Cast.Cast.DeletePrompt:output_type -> google.protobuf.Empty 207, // 247: Cast.Cast.SetLayout:output_type -> google.protobuf.Empty
85, // 248: Cast.Cast.GetPrompt:output_type -> Cast.GetPromptResp 207, // 248: Cast.Cast.UpdatePrompt:output_type -> google.protobuf.Empty
88, // 249: Cast.Cast.ListPrompts:output_type -> Cast.ListPromptsResp 207, // 249: Cast.Cast.DeletePrompt:output_type -> google.protobuf.Empty
90, // 250: Cast.Cast.UpdatePromptBatch:output_type -> Cast.UpdatePromptBatchResp 85, // 250: Cast.Cast.GetPrompt:output_type -> Cast.GetPromptResp
93, // 251: Cast.Cast.UpdateArtist:output_type -> Cast.UpdateArtistResp 88, // 251: Cast.Cast.ListPrompts:output_type -> Cast.ListPromptsResp
95, // 252: Cast.Cast.GetArtist:output_type -> Cast.GetArtistResp 90, // 252: Cast.Cast.UpdatePromptBatch:output_type -> Cast.UpdatePromptBatchResp
97, // 253: Cast.Cast.CreateWorkAnalysis:output_type -> Cast.CreateWorkAnalysisResp 93, // 253: Cast.Cast.UpdateArtist:output_type -> Cast.UpdateArtistResp
207, // 254: Cast.Cast.UpdateWorkAnalysis:output_type -> google.protobuf.Empty 95, // 254: Cast.Cast.GetArtist:output_type -> Cast.GetArtistResp
207, // 255: Cast.Cast.UpdateWorkAnalysisStatus:output_type -> google.protobuf.Empty 97, // 255: Cast.Cast.CreateWorkAnalysis:output_type -> Cast.CreateWorkAnalysisResp
113, // 256: Cast.Cast.GetWorkAnalysis:output_type -> Cast.GetWorkAnalysisDetailResp 207, // 256: Cast.Cast.UpdateWorkAnalysis:output_type -> google.protobuf.Empty
112, // 257: Cast.Cast.GetLatestWorkAnalysis:output_type -> Cast.GetWorkAnalysisResp 207, // 257: Cast.Cast.UpdateWorkAnalysisStatus:output_type -> google.protobuf.Empty
116, // 258: Cast.Cast.ListWorkAnalysis:output_type -> Cast.ListWorkAnalysisResp 113, // 258: Cast.Cast.GetWorkAnalysis:output_type -> Cast.GetWorkAnalysisDetailResp
207, // 259: Cast.Cast.DeleteWorkAnalysis:output_type -> google.protobuf.Empty 112, // 259: Cast.Cast.GetLatestWorkAnalysis:output_type -> Cast.GetWorkAnalysisResp
207, // 260: Cast.Cast.UpdateWorkAnalysisApprovalID:output_type -> google.protobuf.Empty 116, // 260: Cast.Cast.ListWorkAnalysis:output_type -> Cast.ListWorkAnalysisResp
120, // 261: Cast.Cast.ArtistDataList:output_type -> Cast.ArtistDataListResp 207, // 261: Cast.Cast.DeleteWorkAnalysis:output_type -> google.protobuf.Empty
123, // 262: Cast.Cast.MediaDataList:output_type -> Cast.MediaDataListResp 207, // 262: Cast.Cast.UpdateWorkAnalysisApprovalID:output_type -> google.protobuf.Empty
125, // 263: Cast.Cast.DataOverview:output_type -> Cast.DataOverviewResp 120, // 263: Cast.Cast.ArtistDataList:output_type -> Cast.ArtistDataListResp
127, // 264: Cast.Cast.ArtistMetricsSeries:output_type -> Cast.ArtistMetricsSeriesResp 123, // 264: Cast.Cast.MediaDataList:output_type -> Cast.MediaDataListResp
132, // 265: Cast.Cast.ArtistMetricsDailyWindow:output_type -> Cast.ArtistMetricsDailyWindowResp 125, // 265: Cast.Cast.DataOverview:output_type -> Cast.DataOverviewResp
135, // 266: Cast.Cast.TobeConfirmedList:output_type -> Cast.TobeConfirmedListResp 127, // 266: Cast.Cast.ArtistMetricsSeries:output_type -> Cast.ArtistMetricsSeriesResp
139, // 267: Cast.Cast.UpsertMediaMetricsDailyBatch:output_type -> Cast.UpsertMediaMetricsDailyBatchResp 132, // 267: Cast.Cast.ArtistMetricsDailyWindow:output_type -> Cast.ArtistMetricsDailyWindowResp
142, // 268: Cast.Cast.UpsertWorkMetricsDailyBatch:output_type -> Cast.UpsertWorkMetricsDailyBatchResp 135, // 268: Cast.Cast.TobeConfirmedList:output_type -> Cast.TobeConfirmedListResp
153, // 269: Cast.Cast.ListMediaMetricsDaily:output_type -> Cast.ListMediaMetricsDailyResp 139, // 269: Cast.Cast.UpsertMediaMetricsDailyBatch:output_type -> Cast.UpsertMediaMetricsDailyBatchResp
156, // 270: Cast.Cast.ListWorkMetricsDaily:output_type -> Cast.ListWorkMetricsDailyResp 142, // 270: Cast.Cast.UpsertWorkMetricsDailyBatch:output_type -> Cast.UpsertWorkMetricsDailyBatchResp
166, // 271: Cast.Cast.CalculateMediaMetricsByWorks:output_type -> Cast.CalculateMediaMetricsByWorksResp 153, // 271: Cast.Cast.ListMediaMetricsDaily:output_type -> Cast.ListMediaMetricsDailyResp
145, // 272: Cast.Cast.GetArtistAyrShareInfo:output_type -> Cast.GetArtistAyrShareInfoResp 156, // 272: Cast.Cast.ListWorkMetricsDaily:output_type -> Cast.ListWorkMetricsDailyResp
147, // 273: Cast.Cast.GetArtistAyrShareInfoByPlatformIDs:output_type -> Cast.GetArtistAyrShareInfoByPlatformIDsResp 166, // 273: Cast.Cast.CalculateMediaMetricsByWorks:output_type -> Cast.CalculateMediaMetricsByWorksResp
150, // 274: Cast.Cast.ListWorkPlatformInfo:output_type -> Cast.ListWorkPlatformInfoResp 145, // 274: Cast.Cast.GetArtistAyrShareInfo:output_type -> Cast.GetArtistAyrShareInfoResp
158, // 275: Cast.Cast.UpsertTaskList:output_type -> Cast.UpsertTaskListResp 147, // 275: Cast.Cast.GetArtistAyrShareInfoByPlatformIDs:output_type -> Cast.GetArtistAyrShareInfoByPlatformIDsResp
161, // 276: Cast.Cast.GetTaskList:output_type -> Cast.GetTaskListResp 150, // 276: Cast.Cast.ListWorkPlatformInfo:output_type -> Cast.ListWorkPlatformInfoResp
163, // 277: Cast.Cast.ListTaskList:output_type -> Cast.ListTaskListResp 158, // 277: Cast.Cast.UpsertTaskList:output_type -> Cast.UpsertTaskListResp
207, // 278: Cast.Cast.DeleteTaskList:output_type -> google.protobuf.Empty 161, // 278: Cast.Cast.GetTaskList:output_type -> Cast.GetTaskListResp
168, // 279: Cast.Cast.UpdateCastTag:output_type -> Cast.UpdateCastTagResp 163, // 279: Cast.Cast.ListTaskList:output_type -> Cast.ListTaskListResp
171, // 280: Cast.Cast.ListCastTags:output_type -> Cast.ListCastTagsResp 207, // 280: Cast.Cast.DeleteTaskList:output_type -> google.protobuf.Empty
173, // 281: Cast.Cast.UpdateCastTagBatch:output_type -> Cast.UpdateCastTagBatchResp 168, // 281: Cast.Cast.UpdateCastTag:output_type -> Cast.UpdateCastTagResp
207, // 282: Cast.Cast.BatchUpdateCastTags:output_type -> google.protobuf.Empty 171, // 282: Cast.Cast.ListCastTags:output_type -> Cast.ListCastTagsResp
207, // 283: Cast.Cast.UpdateCastTagStatus:output_type -> google.protobuf.Empty 173, // 283: Cast.Cast.UpdateCastTagBatch:output_type -> Cast.UpdateCastTagBatchResp
176, // 284: Cast.Cast.RecalculateCastTagQuoteCount:output_type -> Cast.RecalculateCastTagQuoteCountResp 207, // 284: Cast.Cast.BatchUpdateCastTags:output_type -> google.protobuf.Empty
178, // 285: Cast.Cast.CreateCompetitiveReport:output_type -> Cast.CreateCompetitiveReportResp 207, // 285: Cast.Cast.UpdateCastTagStatus:output_type -> google.protobuf.Empty
193, // 286: Cast.Cast.ImportCompetitiveReportBatch:output_type -> Cast.ImportCompetitiveReportBatchResp 176, // 286: Cast.Cast.RecalculateCastTagQuoteCount:output_type -> Cast.RecalculateCastTagQuoteCountResp
207, // 287: Cast.Cast.UpdateCompetitiveReportStatus:output_type -> google.protobuf.Empty 178, // 287: Cast.Cast.CreateCompetitiveReport:output_type -> Cast.CreateCompetitiveReportResp
187, // 288: Cast.Cast.GetCompetitiveReport:output_type -> Cast.GetCompetitiveReportDetailResp 193, // 288: Cast.Cast.ImportCompetitiveReportBatch:output_type -> Cast.ImportCompetitiveReportBatchResp
186, // 289: Cast.Cast.GetCompetitiveReportForApp:output_type -> Cast.GetCompetitiveReportForAppResp 207, // 289: Cast.Cast.UpdateCompetitiveReportStatus:output_type -> google.protobuf.Empty
190, // 290: Cast.Cast.ListCompetitiveReport:output_type -> Cast.ListCompetitiveReportResp 187, // 290: Cast.Cast.GetCompetitiveReport:output_type -> Cast.GetCompetitiveReportDetailResp
207, // 291: Cast.Cast.DeleteCompetitiveReport:output_type -> google.protobuf.Empty 186, // 291: Cast.Cast.GetCompetitiveReportForApp:output_type -> Cast.GetCompetitiveReportForAppResp
207, // 292: Cast.Cast.UpdateCompetitiveReportApprovalID:output_type -> google.protobuf.Empty 190, // 292: Cast.Cast.ListCompetitiveReport:output_type -> Cast.ListCompetitiveReportResp
196, // 293: Cast.Cast.CountCompetitiveReportByWorkUuids:output_type -> Cast.CountCompetitiveReportByWorkUuidsResp 207, // 293: Cast.Cast.DeleteCompetitiveReport:output_type -> google.protobuf.Empty
208, // [208:294] is the sub-list for method output_type 207, // 294: Cast.Cast.UpdateCompetitiveReportApprovalID:output_type -> google.protobuf.Empty
122, // [122:208] is the sub-list for method input_type 196, // 295: Cast.Cast.CountCompetitiveReportByWorkUuids:output_type -> Cast.CountCompetitiveReportByWorkUuidsResp
122, // [122:122] is the sub-list for extension type_name 210, // [210:296] is the sub-list for method output_type
122, // [122:122] is the sub-list for extension extendee 124, // [124:210] is the sub-list for method input_type
0, // [0:122] is the sub-list for field type_name 124, // [124:124] is the sub-list for extension type_name
124, // [124:124] is the sub-list for extension extendee
0, // [0:124] is the sub-list for field type_name
} }
func init() { file_pb_fiee_cast_proto_init() } func init() { file_pb_fiee_cast_proto_init() }

View File

@ -4586,6 +4586,44 @@ func (m *WorkInfoResp) validate(all bool) error {
// no validation rules for WorkCategory // no validation rules for WorkCategory
for idx, item := range m.GetPlatformInfoData() {
_, _ = idx, item
if all {
switch v := interface{}(item).(type) {
case interface{ ValidateAll() error }:
if err := v.ValidateAll(); err != nil {
errors = append(errors, WorkInfoRespValidationError{
field: fmt.Sprintf("PlatformInfoData[%v]", idx),
reason: "embedded message failed validation",
cause: err,
})
}
case interface{ Validate() error }:
if err := v.Validate(); err != nil {
errors = append(errors, WorkInfoRespValidationError{
field: fmt.Sprintf("PlatformInfoData[%v]", idx),
reason: "embedded message failed validation",
cause: err,
})
}
}
} else if v, ok := interface{}(item).(interface{ Validate() error }); ok {
if err := v.Validate(); err != nil {
return WorkInfoRespValidationError{
field: fmt.Sprintf("PlatformInfoData[%v]", idx),
reason: "embedded message failed validation",
cause: err,
}
}
}
}
// no validation rules for Title
// no validation rules for PublishStatus
if len(errors) > 0 { if len(errors) > 0 {
return WorkInfoRespMultiError(errors) return WorkInfoRespMultiError(errors)
} }
@ -5435,7 +5473,7 @@ func (m *PlatformInfo) validate(all bool) error {
// no validation rules for PublishMediaId // no validation rules for PublishMediaId
// no validation rules for PublishStatus // no validation rules for PublishMediaStatus
// no validation rules for Remark // no validation rules for Remark
@ -19391,6 +19429,8 @@ func (m *UpsertTaskListReq) validate(all bool) error {
// no validation rules for OperatorName // no validation rules for OperatorName
// no validation rules for ExtraData
if len(errors) > 0 { if len(errors) > 0 {
return UpsertTaskListReqMultiError(errors) return UpsertTaskListReqMultiError(errors)
} }
@ -19717,6 +19757,8 @@ func (m *TaskListInfo) validate(all bool) error {
// no validation rules for UpdatedAt // no validation rules for UpdatedAt
// no validation rules for ExtraData
if len(errors) > 0 { if len(errors) > 0 {
return TaskListInfoMultiError(errors) return TaskListInfoMultiError(errors)
} }

View File

@ -27,7 +27,7 @@ func InitTasks() error {
cm := GetCronManager() cm := GetCronManager()
err := cm.AddTask("refreshWorkApprovalStatus", "0 */1 * * * *", RefreshWorkApprovalStatusTask) err := cm.AddTask("refreshWorkApprovalStatus", "0 */1 * * * *", RefreshWorkApprovalStatusTask)
err = cm.AddTask("artistAutoConfirm", "0 */1 * * * *", ArtistAutoConfirmTask) err = cm.AddTask("artistAutoConfirm", "0 */1 * * * *", ArtistAutoConfirmTask)
err = cm.AddTask("refreshPublishStatus", "0 */1 * * * *", RefreshPublishStatusTask) err = cm.AddTask("refreshPublishStatus", "0 */1 * * * *", PublishTask)
err = cm.AddTask("scheduledPublish", "0 */1 * * * *", ScheduledPublishTask) err = cm.AddTask("scheduledPublish", "0 */1 * * * *", ScheduledPublishTask)
err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask) err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask)
@ -272,7 +272,11 @@ func RefreshPublishStatusTask() {
//zap.L().Info("刷新发布状态成功") //zap.L().Info("刷新发布状态成功")
} }
// ScheduledPublishTask 定时发布任务从Redis Sorted Set中获取所有workUuid并根据score判断处理 // PublishTask 定时发布任务从Redis Sorted Set中获取所有workUuid并根据score判断处理
func PublishTask() {
go RefreshPublishStatusTask() // 刷新发布状态
go TaskStatus() // 异步任务状态
}
func ScheduledPublishTask() { func ScheduledPublishTask() {
// 加上锁 // 加上锁
lockKey := "scheduled_publish:lock" lockKey := "scheduled_publish:lock"
@ -303,7 +307,7 @@ func ScheduledPublishTask() {
publishCount := 0 publishCount := 0
expiredCount := 0 expiredCount := 0
const batchSize = 10 // 每批发布10个 const batchSize = 8 // 每批发布8个与PublishWork的workerCount保持一致
zap.L().Info("发现定时发布任务", zap.Int("total_count", len(workList))) zap.L().Info("发现定时发布任务", zap.Int("total_count", len(workList)))
@ -382,6 +386,61 @@ func ScheduledPublishTask() {
zap.Int("total_count", len(workList))) zap.Int("total_count", len(workList)))
} }
func TaskStatus() {
var actions []string = []string{"publishBatch1", "publishBatch2"}
for _, action := range actions {
resp, err := service.CastProvider.ListTaskList(context.Background(), &cast.ListTaskListReq{
Action: action,
Status: 1,
Page: 1,
PageSize: 100,
})
if err != nil {
zap.L().Error("获取任务列表失败", zap.Error(err))
return
}
for _, v := range resp.Data {
var extraData modelCast.PublishTaskDto
if v.ExtraData == "" {
continue
}
_ = json.Unmarshal([]byte(v.ExtraData), &extraData)
var allDone = true
for _, workUuid := range extraData.WorkUuids {
infoResp, _err := service.CastProvider.WorkInfo(context.Background(), &cast.WorkInfoReq{WorkUuid: workUuid})
if _err != nil {
zap.L().Error("获取作品信息失败", zap.Error(_err))
allDone = false
break
}
if infoResp.PublishStatus != cast.PublishStatusENUM_PublishMediaStatus_DONE {
allDone = false
break
}
}
var excelUrl string
if allDone {
excelUrl, err = serverCast.PublishTaskExcel(extraData.WorkUuids, true, v.Action)
if err != nil {
zap.L().Error("生成发布任务Excel失败", zap.Error(err))
continue
}
_, err = service.CastProvider.UpsertTaskList(context.Background(), &cast.UpsertTaskListReq{
Uuid: v.Uuid,
Action: v.Action,
Url: excelUrl,
Status: 3,
})
if err != nil {
zap.L().Error("更新任务状态失败", zap.Error(err))
continue
}
zap.L().Info("任务已完成,更新状态为完成", zap.String("task_uuid", v.Uuid), zap.String("excel_url", excelUrl))
}
}
}
}
// WorkPublishQueueConsumer 监听work:publish:queue队列的消费者 // WorkPublishQueueConsumer 监听work:publish:queue队列的消费者
func WorkPublishQueueConsumer() { func WorkPublishQueueConsumer() {
zap.L().Info("开始监听work:publish:queue队列批量处理模式") zap.L().Info("开始监听work:publish:queue队列批量处理模式")
@ -506,5 +565,5 @@ func AyrshareMetricsCollectorTask() {
} }
func RefreshArtistOrderTask() { func RefreshArtistOrderTask() {
service.CastProvider.Tools(context.Background(), &cast.ToolsReq{Action: "refreshArtistOrder"}) _, _ = service.CastProvider.Tools(context.Background(), &cast.ToolsReq{Action: "artistOrderInfo"})
} }

13
pkg/model/cast/task.go Normal file
View File

@ -0,0 +1,13 @@
package cast
type PublishTaskDto struct {
WorkUuids []string
MediaAccountUuids []string
PlatformIds []string
}
var TaskActionName = map[string]string{
"importWorkBatch": "批量导入图文",
"publishBatch1": "批量发布",
"publishBatch2": "多账号同步",
}

View File

@ -63,6 +63,7 @@ func MediaRouter(r *gin.RouterGroup) {
{ {
task.POST("list", serviceCast.TaskList) task.POST("list", serviceCast.TaskList)
task.POST("delete", serviceCast.DeleteTasK) task.POST("delete", serviceCast.DeleteTasK)
task.POST("download", serviceCast.DownloadTaskFile)
} }
layout := auth.Group("layout") layout := auth.Group("layout")

View File

@ -169,7 +169,7 @@ func UpdateMediaAccount(ctx *gin.Context) {
} }
if userResp != nil && len(userResp.Data) > 0 { if userResp != nil && len(userResp.Data) > 0 {
for _, v := range userResp.Data { for _, v := range userResp.Data {
if v.PlatformID == uint32(req.PlatformID) { if v.PlatformID == uint32(req.PlatformID) && v.Expired == 1 {
service.Error(ctx, errors.New("账号已存在")) service.Error(ctx, errors.New("账号已存在"))
return return
} }
@ -258,6 +258,10 @@ func OAuthAccount(ctx *gin.Context) {
service.Error(ctx, errors.New("未找到该账号")) service.Error(ctx, errors.New("未找到该账号"))
return return
} }
if mediaResp.Data[0].Expired != 1 {
service.Error(ctx, errors.New("账号已过期"))
return
}
if err = SyncAsAuth(mediaResp.Data[0].ArtistUuid); err != nil { if err = SyncAsAuth(mediaResp.Data[0].ArtistUuid); err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return

View File

@ -2,12 +2,23 @@ package cast
import ( import (
"context" "context"
"encoding/json"
"errors"
"fmt" "fmt"
"fonchain-fiee/cmd/config"
"fonchain-fiee/pkg/service/upload"
"os"
"strings"
"time"
"fonchain-fiee/api/cast" "fonchain-fiee/api/cast"
modelCast "fonchain-fiee/pkg/model/cast"
"fonchain-fiee/pkg/model/login" "fonchain-fiee/pkg/model/login"
"fonchain-fiee/pkg/service" "fonchain-fiee/pkg/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2"
"go.uber.org/zap"
) )
func TaskList(ctx *gin.Context) { func TaskList(ctx *gin.Context) {
@ -42,5 +53,148 @@ func DeleteTasK(ctx *gin.Context) {
return return
} }
service.Success(ctx, resp) service.Success(ctx, resp)
return }
func DownloadTaskFile(ctx *gin.Context) {
var req *cast.GetTaskListReq
var err error
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
resp, err := service.CastProvider.GetTaskList(context.Background(), req)
if err != nil {
service.Error(ctx, err)
return
}
if resp == nil || resp.Data == nil {
service.Error(ctx, errors.New("没有此任务"))
return
}
var taskInfo modelCast.PublishTaskDto
if resp.Data.ExtraData != "" {
_ = json.Unmarshal([]byte(resp.Data.ExtraData), &taskInfo)
}
exportUrl, err := PublishTaskExcel(taskInfo.WorkUuids, false, resp.Data.Action)
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, gin.H{
"url": exportUrl,
})
}
func PublishTaskExcel(workUuids []string, uploadOss bool, action string) (string, error) {
// 创建Excel文件
f := excelize.NewFile()
sheetName := "Sheet1"
f.SetSheetName("Sheet1", sheetName)
// 设置表头
headers := []interface{}{
"艺人编号", "艺人姓名", "内容类型", "内容标题",
"执行结果", "TIKTOK", "YOUTUBE", "INS", "DM", "BULESKY",
}
sw, err := f.NewStreamWriter(sheetName)
if err != nil {
return "", err
}
if err = sw.SetRow("A1", headers); err != nil {
return "", err
}
// 遍历所有作品,收集数据
rowIndex := 2
for _, workUuid := range workUuids {
var workResp *cast.WorkDetailResp
workResp, err = service.CastProvider.WorkDetail(context.Background(), &cast.WorkDetailReq{WorkUuid: workUuid})
if err != nil {
continue // 如果某个作品获取失败,跳过继续处理其他作品
}
// 内容类型
contentType := ""
if workResp.WorkCategory == 1 {
contentType = "图文"
} else if workResp.WorkCategory == 2 {
contentType = "视频"
}
// 执行结果
executionResult := modelCast.WorkStatusMM[int(workResp.WorkStatus)]
tiktokStatus := ""
youtubeStatus := ""
insStatus := ""
dmStatus := ""
blueskyStatus := ""
// 获取平台信息和艺人姓名
artistName := ""
var infoResp *cast.WorkInfoResp
infoResp, err = service.CastProvider.WorkInfo(context.Background(), &cast.WorkInfoReq{WorkUuid: workUuid})
if err == nil && infoResp != nil {
artistName = infoResp.ArtistName
if infoResp.PlatformInfoData != nil {
for _, platform := range infoResp.PlatformInfoData {
statusText := modelCast.PlatformPublishStatusMM[platform.PublishMediaStatus]
switch cast.PlatformIDENUM(platform.PlatformID) {
case cast.PlatformIDENUM_TIKTOK:
tiktokStatus = statusText
case cast.PlatformIDENUM_YOUTUBE:
youtubeStatus = statusText
case cast.PlatformIDENUM_INS:
insStatus = statusText
case cast.PlatformIDENUM_DM:
dmStatus = statusText
case cast.PlatformIDENUM_BULESKY:
blueskyStatus = statusText
}
}
}
}
row := []interface{}{
workResp.ArtistSubNum,
artistName,
contentType,
workResp.Title,
executionResult,
tiktokStatus,
youtubeStatus,
insStatus,
dmStatus,
blueskyStatus,
}
cell, _ := excelize.CoordinatesToCellName(1, rowIndex)
if err = sw.SetRow(cell, row); err != nil {
continue
}
rowIndex++
}
if err = sw.Flush(); err != nil {
zap.L().Error("PublishTaskExcel Flush err", zap.Error(err))
return "", errors.New("生成Excel文件失败")
}
tempDir := "./runtime/task"
if _, err = os.Stat(tempDir); os.IsNotExist(err) {
if err = os.MkdirAll(tempDir, 0755); err != nil {
return "", err
}
}
TaskActionName, ok := modelCast.TaskActionName[action]
if !ok {
TaskActionName = "未知任务"
}
filename := fmt.Sprintf("%s_%s.xlsx", TaskActionName, time.Now().Format("20060102150405"))
filePath := tempDir + "/" + filename
var exportUrl string = fmt.Sprintf("%s/api/fiee/static/%s", config.AppConfig.System.FieeHost, strings.Replace(filePath, "./runtime/", "", 1))
if err = f.SaveAs(filePath); err != nil {
zap.L().Error("PublishTaskExcel SaveAs err", zap.Error(err))
return "", errors.New("保存Excel文件失败")
}
if uploadOss {
// 上传到阿里云
exportUrl, err = upload.PutBos(filePath, "excel", true)
if err != nil {
return "", err
}
}
return exportUrl, nil
} }

View File

@ -16,6 +16,10 @@ import (
func Test(ctx *gin.Context) { func Test(ctx *gin.Context) {
action := ctx.PostForm("action") action := ctx.PostForm("action")
if action == "" {
return
}
if action == "getPost" { if action == "getPost" {
id := ctx.PostForm("id") id := ctx.PostForm("id")
profileKey := ctx.PostForm("profileKey") profileKey := ctx.PostForm("profileKey")
@ -70,19 +74,6 @@ func Test(ctx *gin.Context) {
return return
} }
if action == "" {
resp, err := service.CastProvider.WorkList(context.Background(), &cast.WorkListReq{
Page: 1,
PageSize: 1000,
SubmitTimeMonths: []string{"2026-01", "2025-12"},
})
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, resp)
return
}
if action == "getProfile" { if action == "getProfile" {
//profileKey := ctx.PostForm("profileKey") //profileKey := ctx.PostForm("profileKey")
resp, err := service.AyrshareProvider.GetProfiles(context.Background(), &aryshare.GetProfilesRequest{ resp, err := service.AyrshareProvider.GetProfiles(context.Background(), &aryshare.GetProfilesRequest{
@ -166,6 +157,16 @@ func Test(ctx *gin.Context) {
service.Success(ctx, "ok") service.Success(ctx, "ok")
} }
if action == "RefreshWorkList" {
resp, err := service.CastProvider.RefreshWorkList(context.Background(), &cast.RefreshWorkListReq{PublishStatus: 1})
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, resp)
return
}
service.Success(ctx, "unknow") service.Success(ctx, "unknow")
return return
} }

View File

@ -21,6 +21,7 @@ import (
"fonchain-fiee/pkg/service/check" "fonchain-fiee/pkg/service/check"
"fonchain-fiee/pkg/service/upload" "fonchain-fiee/pkg/service/upload"
"fonchain-fiee/pkg/utils" "fonchain-fiee/pkg/utils"
utilsImg "fonchain-fiee/pkg/utils/img"
"fonchain-fiee/pkg/utils/stime" "fonchain-fiee/pkg/utils/stime"
"image" "image"
"image/jpeg" "image/jpeg"
@ -109,11 +110,10 @@ func UpdateWorkImageCore(ctx *gin.Context, req *cast.UpdateWorkImageReq) (*cast.
ID: artistId, ID: artistId,
Domain: "app", Domain: "app",
}) })
zap.L().Info("UpdateWorkImage infoResp", zap.Any("infoResp", infoResp)) zap.L().Info("UpdateWorkImage infoResp1", zap.Any("infoResp", infoResp))
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.ArtistName = infoResp.Name req.ArtistName = infoResp.Name
req.ArtistPhone = infoResp.TelNum req.ArtistPhone = infoResp.TelNum
req.ArtistPhoneAreaCode = infoResp.TelAreaCode req.ArtistPhoneAreaCode = infoResp.TelAreaCode
@ -127,6 +127,7 @@ func UpdateWorkImageCore(ctx *gin.Context, req *cast.UpdateWorkImageReq) (*cast.
resp, err := service.CastProvider.UpdateWorkImage(newCtx, req) resp, err := service.CastProvider.UpdateWorkImage(newCtx, req)
zap.L().Info("UpdateWorkImage resp", zap.Any("resp", resp)) zap.L().Info("UpdateWorkImage resp", zap.Any("resp", resp))
if err != nil { if err != nil {
zap.L().Error("UpdateWorkImage err", zap.Error(err))
return nil, err return nil, err
} }
return resp, nil return resp, nil
@ -434,10 +435,26 @@ func Publish(ctx *gin.Context) {
return return
} }
newCtx := NewCtxWithUserInfo(ctx) newCtx := NewCtxWithUserInfo(ctx)
loginInfo := login.GetUserInfoFromC(ctx)
var extraBytes []byte
extraBytes, _ = json.Marshal(req)
_, err = service.CastProvider.UpsertTaskList(newCtx, &cast.UpsertTaskListReq{
Action: "publishBatch1",
Url: "",
Status: 1,
OperatorID: fmt.Sprint(loginInfo.ID),
OperatorName: loginInfo.Name,
ExtraData: string(extraBytes),
})
if err != nil {
service.Error(ctx, err)
return
}
if err = PublishWork(newCtx, req); err != nil { if err = PublishWork(newCtx, req); err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return
} }
service.Success(ctx, req) service.Success(ctx, req)
return return
} }
@ -445,7 +462,6 @@ func Publish(ctx *gin.Context) {
// PublishWork 统一发布 // PublishWork 统一发布
func PublishWork(ctx context.Context, req *cast.PublishReq) error { func PublishWork(ctx context.Context, req *cast.PublishReq) error {
var ( var (
wg sync.WaitGroup
errsMu sync.Mutex errsMu sync.Mutex
errs []error errs []error
) )
@ -453,20 +469,45 @@ func PublishWork(ctx context.Context, req *cast.PublishReq) error {
if len(req.WorkUuids) == 0 { if len(req.WorkUuids) == 0 {
return errors.New("请选择作品") return errors.New("请选择作品")
} }
jobs := make(chan string, len(req.WorkUuids))
// 添加日志 // 添加日志
zap.L().Info("开始发布作品", zap.Int("总数", len(req.WorkUuids))) zap.L().Info("开始发布作品", zap.Int("总数", len(req.WorkUuids)))
startTime := time.Now().Unix() startTime := time.Now().Unix()
workerCount := 10
if len(req.WorkUuids) < workerCount { // 每批次协程数量设为8
workerCount = len(req.WorkUuids) // 避免创建多余的协程 workerCount := 8
batchSize := workerCount // 每批处理8个任务
// 分批处理
for batchStart := 0; batchStart < len(req.WorkUuids); batchStart += batchSize {
batchEnd := batchStart + batchSize
if batchEnd > len(req.WorkUuids) {
batchEnd = len(req.WorkUuids)
} }
for i := 0; i < workerCount; i++ {
currentBatch := req.WorkUuids[batchStart:batchEnd]
batchNum := batchStart/batchSize + 1
totalBatches := (len(req.WorkUuids) + batchSize - 1) / batchSize
zap.L().Info("开始处理批次",
zap.Int("批次", batchNum),
zap.Int("总批次", totalBatches),
zap.Int("本批数量", len(currentBatch)))
// 处理当前批次
var wg sync.WaitGroup
jobs := make(chan string, len(currentBatch))
currentWorkerCount := workerCount
if len(currentBatch) < workerCount {
currentWorkerCount = len(currentBatch) // 避免创建多余的协程
}
for i := 0; i < currentWorkerCount; i++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
for workUuid := range jobs { for workUuid := range jobs {
if err := PostAS(workUuid); err != nil { if err := PostAS(ctx, workUuid); err != nil {
errsMu.Lock() errsMu.Lock()
errs = append(errs, err) errs = append(errs, err)
errsMu.Unlock() errsMu.Unlock()
@ -474,11 +515,23 @@ func PublishWork(ctx context.Context, req *cast.PublishReq) error {
} }
}() }()
} }
for _, workUuid := range req.WorkUuids {
for _, workUuid := range currentBatch {
jobs <- workUuid jobs <- workUuid
} }
close(jobs) close(jobs)
wg.Wait() wg.Wait()
zap.L().Info("批次处理完成", zap.Int("批次", batchNum))
// 如果不是最后一批等待10-15秒再进行下一批
if batchEnd < len(req.WorkUuids) {
waitTime := 10 + time.Duration(time.Now().UnixNano()%6) // 随机10-15秒
zap.L().Info("等待后再处理下一批", zap.Int64("等待秒数", int64(waitTime)))
time.Sleep(waitTime * time.Second)
}
}
// 统计结果 // 统计结果
successCount := len(req.WorkUuids) - len(errs) successCount := len(req.WorkUuids) - len(errs)
zap.L().Info("发布完成", zap.L().Info("发布完成",
@ -493,9 +546,9 @@ func PublishWork(ctx context.Context, req *cast.PublishReq) error {
return nil return nil
} }
func PostAS(workUuid string) error { func PostAS(ctx context.Context, workUuid string) error {
var err error var err error
_, err = service.CastProvider.Publish(context.Background(), &cast.PublishReq{WorkUuids: []string{workUuid}}) _, err = service.CastProvider.Publish(ctx, &cast.PublishReq{WorkUuids: []string{workUuid}})
if err != nil { if err != nil {
zap.L().Error("Publish err", zap.String("workUuid", workUuid), zap.Error(err)) zap.L().Error("Publish err", zap.String("workUuid", workUuid), zap.Error(err))
return err return err
@ -528,7 +581,12 @@ func PostAS(workUuid string) error {
if workDetail.WorkCategory == 1 { if workDetail.WorkCategory == 1 {
isVideo = false isVideo = false
// 先用服务器上的文件,不上传到第三方 // 先用服务器上的文件,不上传到第三方
//mediaUrls = workDetail.Images
mediaUrls, err = ProcessImg(workDetail.Images)
if err != nil {
mediaUrls = workDetail.Images mediaUrls = workDetail.Images
err = nil
}
/* for _, imageUrl := range workDetail.Images { /* for _, imageUrl := range workDetail.Images {
urlResp, err = UploadMediaByURL(context.Background(), imageUrl, "", "") urlResp, err = UploadMediaByURL(context.Background(), imageUrl, "", "")
if err != nil { if err != nil {
@ -544,6 +602,10 @@ func PostAS(workUuid string) error {
isVideo = true isVideo = true
mediaUrls = []string{workDetail.VideoUrl} mediaUrls = []string{workDetail.VideoUrl}
coverUrl = workDetail.CoverUrl coverUrl = workDetail.CoverUrl
coverUrls, _ := ProcessImg([]string{workDetail.CoverUrl})
if len(coverUrls) > 0 {
coverUrl = coverUrls[0]
}
// 先用服务器上的文件,不上传到第三方 // 先用服务器上的文件,不上传到第三方
/*urlResp, err = UploadMediaByURL(context.Background(), workDetail.VideoUrl, "", "") /*urlResp, err = UploadMediaByURL(context.Background(), workDetail.VideoUrl, "", "")
if err != nil { if err != nil {
@ -686,7 +748,7 @@ func PostAS(workUuid string) error {
PublishType: 2, PublishType: 2,
PublishResp: _err.Error(), PublishResp: _err.Error(),
PublishMediaId: "", PublishMediaId: "",
PublishStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION, PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION,
Remark: "", Remark: "",
}) })
zap.L().Info("UpdateWorkPlatformInfo", zap.Any("infoReq", infoReq)) zap.L().Info("UpdateWorkPlatformInfo", zap.Any("infoReq", infoReq))
@ -747,7 +809,7 @@ func PostAS(workUuid string) error {
PublishType: 2, PublishType: 2,
PublishResp: string(postBytes), PublishResp: string(postBytes),
PublishMediaId: postResp.Posts[0].Id, PublishMediaId: postResp.Posts[0].Id,
PublishStatus: publishStatus, PublishMediaStatus: publishStatus,
Remark: string(postData), Remark: string(postData),
}) })
} }
@ -806,11 +868,27 @@ func RePublish(ctx *gin.Context) {
service.Error(ctx, err) service.Error(ctx, err)
return return
} }
fmt.Println(resp) loginInfo := login.GetUserInfoFromC(ctx)
var extraBytes []byte
extraBytes, _ = json.Marshal(req)
_, err = service.CastProvider.UpsertTaskList(newCtx, &cast.UpsertTaskListReq{
Action: "publishBatch2",
Url: "",
Status: 1,
OperatorID: fmt.Sprint(loginInfo.ID),
OperatorName: loginInfo.Name,
ExtraData: string(extraBytes),
})
if err != nil {
zap.L().Error("RePublish UpsertTaskList failed", zap.Error(err))
service.Error(ctx, err)
return
}
if err = PublishWork(newCtx, &cast.PublishReq{WorkUuids: resp.WorkUuids}); err != nil { if err = PublishWork(newCtx, &cast.PublishReq{WorkUuids: resp.WorkUuids}); err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return
} }
service.Success(ctx, req) service.Success(ctx, req)
return return
} }
@ -1564,9 +1642,11 @@ func ImportWorkBatch(ctx *gin.Context) {
return return
} }
} }
service.CastProvider.UpsertTaskList(context.Background(), &cast.UpsertTaskListReq{ urlResult, _ = upload.PutBos(excelPath, "excel", true)
_, _ = service.CastProvider.UpsertTaskList(context.Background(), &cast.UpsertTaskListReq{
Uuid: taskResp.Uuid, Uuid: taskResp.Uuid,
Status: 3, Status: 3,
Url: urlResult,
}) })
service.Success(ctx, map[string]interface{}{ service.Success(ctx, map[string]interface{}{
"successCount": resp.SuccessCount, "successCount": resp.SuccessCount,
@ -1600,6 +1680,14 @@ func RefreshPublish() error {
} }
for _, platformInfo := range workInfo.PlatformInfoData { for _, platformInfo := range workInfo.PlatformInfoData {
if platformInfo.PublishMediaID == "" { if platformInfo.PublishMediaID == "" {
var infoReq = &cast.UpdateWorkPlatformInfoReq{
PlatformInfoData: make([]*cast.PlatformInfo, 0),
}
infoReq.PlatformInfoData = append(infoReq.PlatformInfoData, &cast.PlatformInfo{
WorkUuid: workInfo.WorkUuid,
PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_NO,
})
_, _ = service.CastProvider.UpdateWorkPlatformInfo(context.Background(), infoReq)
continue continue
} }
var infoReq = &cast.UpdateWorkPlatformInfoReq{ var infoReq = &cast.UpdateWorkPlatformInfoReq{
@ -1618,7 +1706,7 @@ func RefreshPublish() error {
PublishType: 2, PublishType: 2,
PublishResp: err.Error(), PublishResp: err.Error(),
PublishMediaId: platformInfo.PublishMediaID, PublishMediaId: platformInfo.PublishMediaID,
PublishStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION, PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION,
Remark: "", Remark: "",
PlatformUuid: platformInfo.PlatformUuid, PlatformUuid: platformInfo.PlatformUuid,
}) })
@ -1635,7 +1723,7 @@ func RefreshPublish() error {
PublishType: 2, PublishType: 2,
PublishResp: string(dmData), PublishResp: string(dmData),
PublishMediaId: platformInfo.PublishMediaID, PublishMediaId: platformInfo.PublishMediaID,
PublishStatus: cast.PublishStatusENUM_PublishMediaStatus_DONE, PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_DONE,
Remark: "", Remark: "",
PlatformUuid: platformInfo.PlatformUuid, PlatformUuid: platformInfo.PlatformUuid,
}) })
@ -1688,7 +1776,7 @@ func RefreshPublish() error {
PublishType: 2, PublishType: 2,
PublishResp: _err.Error(), PublishResp: _err.Error(),
PublishMediaId: platformInfo.PublishMediaID, PublishMediaId: platformInfo.PublishMediaID,
PublishStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION, PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION,
Remark: "", Remark: "",
PlatformUuid: platformInfo.PlatformUuid, PlatformUuid: platformInfo.PlatformUuid,
}) })
@ -1708,7 +1796,7 @@ func RefreshPublish() error {
PublishType: 2, PublishType: 2,
PublishResp: string(postBytes), PublishResp: string(postBytes),
PublishMediaId: platformInfo.PublishMediaID, PublishMediaId: platformInfo.PublishMediaID,
PublishStatus: cast.PublishStatusENUM_PublishMediaStatus_FAIL, PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_FAIL,
Remark: "", Remark: "",
PlatformUuid: platformInfo.PlatformUuid, PlatformUuid: platformInfo.PlatformUuid,
}) })
@ -1738,7 +1826,7 @@ func RefreshPublish() error {
PublishType: 2, PublishType: 2,
PublishResp: string(postBytes), PublishResp: string(postBytes),
PublishMediaId: platformInfo.PublishMediaID, PublishMediaId: platformInfo.PublishMediaID,
PublishStatus: publishStatus, PublishMediaStatus: publishStatus,
Remark: "", Remark: "",
PlatformUuid: platformInfo.PlatformUuid, PlatformUuid: platformInfo.PlatformUuid,
}) })
@ -1799,3 +1887,38 @@ func checkAndReuploadImage(imageUrl string, mediaType string) (string, error) {
} }
return compressUrl, nil return compressUrl, nil
} }
func ProcessImg(imgs []string) ([]string, error) {
var newImgs []string
for _, img := range imgs {
newPath, err := utilsImg.ProcessFromURL(
img,
utilsImg.Options{
TargetWidth: 1024,
TargetHeight: 1024,
MaxSizeMB: 1, // 提高到 2MB对于 1024x1024 更合理
Mode: utilsImg.ResizeModePad, // 等比缩放+留白
OutputDir: "./runtime/tmp/images/processed",
MinQuality: 20, // 最低质量阈值
MaxRetries: 15, // 最大尝试次数
AllowResolutionReduction: true, // 允许降低分辨率
ForceJPEG: true, // 强制转换为 JPEG 格式
},
)
if err != nil {
zap.L().Error("processImg err", zap.Error(err), zap.Any("img", img))
newImgs = append(newImgs, img)
err = nil
continue
}
exportUrl, err := upload.PutBos(newPath, "fieework", true)
if err != nil {
zap.L().Error("upload.PutBos err", zap.Error(err), zap.Any("img", img))
newImgs = append(newImgs, img)
err = nil
continue
}
newImgs = append(newImgs, exportUrl)
}
return newImgs, nil
}

555
pkg/utils/img/imageproc.go Normal file
View File

@ -0,0 +1,555 @@
package img
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"image"
"image/color"
"image/gif"
"image/jpeg"
"image/png"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"github.com/disintegration/imaging"
)
// ResizeMode controls how the source image is mapped to the target WxH.
//
// - ResizeModeFit: contain (keep aspect), no cropping; resulting image may be smaller than WxH
// - ResizeModeFill: cover + crop (center crop) to exactly WxH
// - ResizeModePad: keep aspect + pad (letterbox) to exactly WxH (no crop, no stretch)
//
// If you only pass a single dimension (e.g. W>0, H=0), Fit will keep aspect.
// Fill/Pad requires both W and H.
//
// Note: GIF input will be processed as a single frame (first frame).
// If you need animated GIF support, we can extend this later.
type ResizeMode string
const (
ResizeModeFit ResizeMode = "fit"
ResizeModeFill ResizeMode = "fill"
// ResizeModePad keeps aspect ratio (no crop, no stretch) and pads to exactly WxH.
// Typical use: 16:9 -> 1024x1024 with white/black bars.
ResizeModePad ResizeMode = "pad"
)
type Options struct {
TargetWidth int
TargetHeight int
MaxSizeMB float64
Mode ResizeMode
// PadColor is used only when Mode == ResizeModePad.
// Default: white.
PadColor color.Color
// OutputDir is where the processed image will be written.
// Default: ./runtime/tmp/images/processed
OutputDir string
// Timeout controls total download time.
// Default: 30s.
Timeout time.Duration
// MaxDownloadMB caps download size to protect memory/disk.
// Default: max( maxSizeMB*6, 30MB ).
MaxDownloadMB float64
// MinQuality is the minimum JPEG quality to try (1-100).
// Default: 10. If compression still can't meet MaxSizeMB, returns error.
MinQuality int
// MaxRetries controls how many quality adjustments to attempt.
// Default: 15.
MaxRetries int
// AllowResolutionReduction allows reducing resolution further if compression fails.
// Default: false.
AllowResolutionReduction bool
// ForceJPEG forces output to JPEG format even if input is PNG/GIF/etc.
// If image has alpha channel, it will be flattened to white background.
// Default: false.
ForceJPEG bool
}
// ProcessFromURL downloads an image from imgURL, resizes it, compresses it to <= MaxSizeMB,
// and returns the local output path.
//
// Contract:
// - imgURL: http/https
// - TargetWidth/TargetHeight: pixels, >=0
// - MaxSizeMB: >0
// - returns: absolute or relative file path (depending on OutputDir), and error
func ProcessFromURL(imgURL string, opt Options) (string, error) {
if strings.TrimSpace(imgURL) == "" {
return "", errors.New("imgURL is empty")
}
u, err := url.Parse(imgURL)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return "", errors.New("imgURL must be http/https")
}
if opt.MaxSizeMB <= 0 {
return "", errors.New("MaxSizeMB must be > 0")
}
if opt.TargetWidth < 0 || opt.TargetHeight < 0 {
return "", errors.New("TargetWidth/TargetHeight must be >= 0")
}
if opt.TargetWidth == 0 && opt.TargetHeight == 0 {
return "", errors.New("TargetWidth and TargetHeight cannot both be 0")
}
if opt.Mode == "" {
opt.Mode = ResizeModeFit
}
if opt.Mode != ResizeModeFit && opt.Mode != ResizeModeFill && opt.Mode != ResizeModePad {
return "", errors.New("invalid resize Mode")
}
if (opt.Mode == ResizeModeFill || opt.Mode == ResizeModePad) && (opt.TargetWidth == 0 || opt.TargetHeight == 0) {
return "", errors.New("fill/pad mode requires both TargetWidth and TargetHeight")
}
if opt.Timeout <= 0 {
opt.Timeout = 30 * time.Second
}
if opt.OutputDir == "" {
opt.OutputDir = filepath.FromSlash("./runtime/tmp/images/processed")
}
if opt.MaxDownloadMB <= 0 {
opt.MaxDownloadMB = opt.MaxSizeMB * 6
if opt.MaxDownloadMB < 30 {
opt.MaxDownloadMB = 30
}
if opt.MaxDownloadMB > 200 {
opt.MaxDownloadMB = 200
}
}
if opt.MinQuality <= 0 {
opt.MinQuality = 10
}
if opt.MinQuality > 100 {
opt.MinQuality = 100
}
if opt.MaxRetries <= 0 {
opt.MaxRetries = 15
}
// Ensure output dir exists.
if err := os.MkdirAll(opt.OutputDir, os.ModePerm); err != nil {
return "", err
}
ctx, cancel := context.WithTimeout(context.Background(), opt.Timeout)
defer cancel()
data, contentType, err := downloadWithLimit(ctx, imgURL, int64(opt.MaxDownloadMB*1024*1024))
if err != nil {
return "", err
}
img, fmtName, err := decodeImage(data, contentType)
if err != nil {
return "", err
}
// Check if image already meets requirements
if alreadyMeetsRequirements(img, data, opt) {
return "", nil
}
img = applyResize(img, opt)
// Determine output format
outExt := ".jpg"
outFormat := "jpeg"
if opt.ForceJPEG {
// Force JPEG output, flatten alpha if needed
outFormat = "jpeg"
outExt = ".jpg"
if imageHasAlpha(img) {
img = flattenToWhite(img)
}
} else {
// Auto-detect: if image has alpha, output PNG; otherwise JPEG
hasAlpha := imageHasAlpha(img)
if hasAlpha {
outExt = ".png"
outFormat = "png"
}
}
// Create a stable file name based on url + options + content signature.
h := sha256.New()
h.Write([]byte(imgURL))
h.Write([]byte(fmt.Sprintf("|%d|%d|%f|%s|%s", opt.TargetWidth, opt.TargetHeight, opt.MaxSizeMB, opt.Mode, outFormat)))
h.Write(data[:minInt(len(data), 1024)])
name := hex.EncodeToString(h.Sum(nil))[:32] + outExt
outPath := filepath.Join(opt.OutputDir, name)
maxBytes := int64(opt.MaxSizeMB * 1024 * 1024)
encoded, err := encodeUnderSize(img, outFormat, maxBytes, opt.MinQuality, opt.MaxRetries)
if err != nil {
// Fallback: if PNG can't fit, try JPEG (dropping alpha with white background).
if outFormat == "png" {
flattened := flattenToWhite(img)
encoded, err = encodeUnderSize(flattened, "jpeg", maxBytes, opt.MinQuality, opt.MaxRetries)
if err == nil {
outPath = strings.TrimSuffix(outPath, filepath.Ext(outPath)) + ".jpg"
} else {
// If AllowResolutionReduction is true, try reducing resolution
if opt.AllowResolutionReduction {
return tryWithReducedResolution(img, opt, outPath, maxBytes)
}
return "", err
}
} else {
// If AllowResolutionReduction is true, try reducing resolution
if opt.AllowResolutionReduction {
return tryWithReducedResolution(img, opt, outPath, maxBytes)
}
return "", err
}
}
tmpPath := outPath + ".tmp"
if err := os.WriteFile(tmpPath, encoded, 0o644); err != nil {
return "", err
}
if err := os.Rename(tmpPath, outPath); err != nil {
_ = os.Remove(tmpPath)
return "", err
}
_ = fmtName // reserved for future behavior
return outPath, nil
}
func downloadWithLimit(ctx context.Context, imgURL string, maxBytes int64) ([]byte, string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, imgURL, nil)
if err != nil {
return nil, "", err
}
// Reasonable defaults; could be overridden later.
req.Header.Set("User-Agent", "fonchain-tools/1.0")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, "", err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, "", fmt.Errorf("download failed: %s", resp.Status)
}
if resp.ContentLength > 0 && resp.ContentLength > maxBytes {
return nil, "", fmt.Errorf("remote file too large: %d > %d", resp.ContentLength, maxBytes)
}
lr := &io.LimitedReader{R: resp.Body, N: maxBytes + 1}
b, err := io.ReadAll(lr)
if err != nil {
return nil, "", err
}
if int64(len(b)) > maxBytes {
return nil, "", fmt.Errorf("download exceeded limit: %d > %d", len(b), maxBytes)
}
return b, resp.Header.Get("Content-Type"), nil
}
func decodeImage(data []byte, contentType string) (image.Image, string, error) {
// Register gif (jpeg/png already registered) for Decode.
_ = gif.GIF{}
reader := bytes.NewReader(data)
img, fmtName, err := image.Decode(reader)
if err == nil {
return img, fmtName, nil
}
// Some servers set odd content-type; try simple sniff.
_ = contentType
return nil, "", fmt.Errorf("decode image failed: %w", err)
}
func applyResize(img image.Image, opt Options) image.Image {
w := opt.TargetWidth
h := opt.TargetHeight
srcW := img.Bounds().Dx()
srcH := img.Bounds().Dy()
if srcW <= 0 || srcH <= 0 {
return img
}
switch opt.Mode {
case ResizeModeFill:
return imaging.Fill(img, w, h, imaging.Center, imaging.Lanczos)
case ResizeModeFit:
// If only one dimension is provided, keep aspect.
if w == 0 {
w = int(float64(srcW) * (float64(h) / float64(srcH)))
if w < 1 {
w = 1
}
}
if h == 0 {
h = int(float64(srcH) * (float64(w) / float64(srcW)))
if h < 1 {
h = 1
}
}
// imaging.Fit ensures the result fits within w,h without cropping.
return imaging.Fit(img, w, h, imaging.Lanczos)
case ResizeModePad:
bg := opt.PadColor
if bg == nil {
bg = color.White
}
// First, fit within WxH (no crop).
fitted := imaging.Fit(img, w, h, imaging.Lanczos)
// Then, paste centered onto WxH canvas.
canvas := imaging.New(w, h, bg)
x := (w - fitted.Bounds().Dx()) / 2
y := (h - fitted.Bounds().Dy()) / 2
return imaging.Paste(canvas, fitted, image.Pt(x, y))
default:
return img
}
}
func encodeUnderSize(img image.Image, format string, maxBytes int64, minQuality, maxRetries int) ([]byte, error) {
if maxBytes <= 0 {
return nil, errors.New("maxBytes must be > 0")
}
switch format {
case "jpeg":
// Binary search quality.
lo, hi := minQuality, 92
var best []byte
iterations := 0
maxIterations := maxInt(8, maxRetries/2)
for i := 0; i < maxIterations && lo <= hi; i++ {
iterations++
q := (lo + hi) / 2
b, err := encodeJPEG(img, q)
if err != nil {
return nil, err
}
if int64(len(b)) <= maxBytes {
best = b
lo = q + 1
} else {
hi = q - 1
}
}
if best != nil {
return best, nil
}
// Try more aggressive qualities from minQuality down to 1
qualities := []int{}
for q := minQuality; q >= 1; q -= 5 {
qualities = append(qualities, q)
}
// Ensure we try the lowest qualities
if minQuality > 3 {
qualities = append(qualities, 3, 1)
}
var lastSize int64
for _, q := range qualities {
if iterations >= maxRetries {
break
}
iterations++
b, err := encodeJPEG(img, q)
if err != nil {
return nil, err
}
lastSize = int64(len(b))
if lastSize <= maxBytes {
return b, nil
}
}
sizeMB := float64(lastSize) / (1024 * 1024)
targetMB := float64(maxBytes) / (1024 * 1024)
return nil, fmt.Errorf("cannot compress to %.2fMB (best: %.2fMB at quality %d after %d attempts). Consider increasing MaxSizeMB or enabling AllowResolutionReduction",
targetMB, sizeMB, minQuality, iterations)
case "png":
// PNG size depends heavily on content; try best compression.
b, err := encodePNG(img, png.BestCompression)
if err != nil {
return nil, err
}
if int64(len(b)) <= maxBytes {
return b, nil
}
sizeMB := float64(len(b)) / (1024 * 1024)
targetMB := float64(maxBytes) / (1024 * 1024)
return nil, fmt.Errorf("PNG cannot compress to %.2fMB (got %.2fMB). Consider using JPEG format or enabling AllowResolutionReduction",
targetMB, sizeMB)
default:
return nil, errors.New("unsupported output format")
}
}
func encodeJPEG(img image.Image, quality int) ([]byte, error) {
var buf bytes.Buffer
// Use 4:2:0 subsampling (default) for smaller size.
err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality})
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encodePNG(img image.Image, level png.CompressionLevel) ([]byte, error) {
var buf bytes.Buffer
enc := png.Encoder{CompressionLevel: level}
if err := enc.Encode(&buf, img); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func imageHasAlpha(img image.Image) bool {
switch img.(type) {
case *image.NRGBA, *image.NRGBA64, *image.RGBA, *image.RGBA64, *image.Alpha, *image.Alpha16, *image.Paletted:
// Need to inspect pixels if we want exactness; but this is good enough and stable.
return true
default:
return false
}
}
func flattenToWhite(img image.Image) image.Image {
b := img.Bounds()
dst := image.NewRGBA(b)
// Fill with white.
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
dst.Set(x, y, image.White)
}
}
// Draw original image over white background.
return imaging.Overlay(dst, img, image.Pt(0, 0), 1.0)
}
func minInt(a, b int) int {
if a < b {
return a
}
return b
}
func maxInt(a, b int) int {
if a > b {
return a
}
return b
}
// alreadyMeetsRequirements checks if the image already satisfies the size and dimension requirements
func alreadyMeetsRequirements(img image.Image, data []byte, opt Options) bool {
// Check file size
maxBytes := int64(opt.MaxSizeMB * 1024 * 1024)
if int64(len(data)) > maxBytes {
return false
}
// Check dimensions based on mode
srcW := img.Bounds().Dx()
srcH := img.Bounds().Dy()
targetW := opt.TargetWidth
targetH := opt.TargetHeight
switch opt.Mode {
case ResizeModeFit:
// For fit mode, check if image is already within or equal to target dimensions
if targetW > 0 && srcW > targetW {
return false
}
if targetH > 0 && srcH > targetH {
return false
}
// If only one dimension is specified, check aspect ratio compatibility
if targetW > 0 && targetH == 0 && srcW <= targetW {
return true
}
if targetH > 0 && targetW == 0 && srcH <= targetH {
return true
}
if targetW > 0 && targetH > 0 && srcW <= targetW && srcH <= targetH {
return true
}
return false
case ResizeModeFill, ResizeModePad:
// For fill/pad mode, image must be exactly the target dimensions
if srcW != targetW || srcH != targetH {
return false
}
return true
default:
return false
}
}
// tryWithReducedResolution attempts to compress by progressively reducing resolution
func tryWithReducedResolution(img image.Image, opt Options, outPath string, maxBytes int64) (string, error) {
bounds := img.Bounds()
w := bounds.Dx()
h := bounds.Dy()
// Try reducing resolution in steps: 90%, 80%, 70%, 60%, 50%
reductions := []float64{0.9, 0.8, 0.7, 0.6, 0.5}
for _, factor := range reductions {
newW := int(float64(w) * factor)
newH := int(float64(h) * factor)
if newW < 100 || newH < 100 {
break // Don't reduce too much
}
resized := imaging.Resize(img, newW, newH, imaging.Lanczos)
// Try to encode with reduced resolution
encoded, err := encodeUnderSize(resized, "jpeg", maxBytes, opt.MinQuality, opt.MaxRetries/2)
if err == nil {
// Success! Save it
tmpPath := outPath + ".tmp"
if err := os.WriteFile(tmpPath, encoded, 0o644); err != nil {
return "", err
}
if err := os.Rename(tmpPath, outPath); err != nil {
_ = os.Remove(tmpPath)
return "", err
}
return outPath, nil
}
}
targetMB := float64(maxBytes) / (1024 * 1024)
return "", fmt.Errorf("cannot compress to %.2fMB even after reducing resolution to 50%%. Original size too large", targetMB)
}