342 lines
8.8 KiB
Go
342 lines
8.8 KiB
Go
package srv_videoinfo
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// UnmarshalJSON 兼容 id 使用数字字符串,以及 param 里的表单写法。
|
|
func (r *VideoInfoUpdateReq) UnmarshalJSON(data []byte) error {
|
|
data = bytes.TrimSpace(data)
|
|
if len(data) == 0 || bytes.Equal(data, []byte("null")) {
|
|
return nil
|
|
}
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return err
|
|
}
|
|
if value, ok := raw["id"]; ok {
|
|
next, keep, err := normalizeIntRaw(value)
|
|
if err != nil {
|
|
return fmt.Errorf("id %w", err)
|
|
}
|
|
if keep && next != nil && !bytes.Equal(bytes.TrimSpace(next), []byte("null")) {
|
|
if err := json.Unmarshal(next, &r.Id); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if value, ok := raw["param"]; ok && !bytes.Equal(bytes.TrimSpace(value), []byte("null")) {
|
|
if err := json.Unmarshal(value, &r.Param); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalJSON 兼容后台表单里的空字符串、数字字符串,以及分类排序的多种写法。
|
|
func (v *VideoInfoUpdate) UnmarshalJSON(data []byte) error {
|
|
data = bytes.TrimSpace(data)
|
|
if len(data) == 0 || bytes.Equal(data, []byte("null")) {
|
|
return nil
|
|
}
|
|
normalized, err := normalizeVideoUpdateJSON(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
type alias VideoInfoUpdate
|
|
var out alias
|
|
if err := json.Unmarshal(normalized, &out); err != nil {
|
|
return err
|
|
}
|
|
*v = VideoInfoUpdate(out)
|
|
return nil
|
|
}
|
|
|
|
func normalizeVideoUpdateJSON(data []byte) ([]byte, error) {
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return nil, err
|
|
}
|
|
for _, key := range []string{"addedTime", "updatedAt", "issuedAt", "secondUpdatedAt"} {
|
|
value, ok := raw[key]
|
|
if !ok {
|
|
continue
|
|
}
|
|
next, err := normalizeTimeRaw(value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if next == nil {
|
|
delete(raw, key)
|
|
continue
|
|
}
|
|
raw[key] = next
|
|
}
|
|
for _, key := range []string{"categoryId", "sort", "creatorId", "height", "width", "videoTime", "indexNow", "mediaType", "status"} {
|
|
value, ok := raw[key]
|
|
if !ok {
|
|
continue
|
|
}
|
|
next, keep, err := normalizeIntRaw(value)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s %w", key, err)
|
|
}
|
|
if !keep {
|
|
continue
|
|
}
|
|
if next == nil {
|
|
delete(raw, key)
|
|
continue
|
|
}
|
|
raw[key] = next
|
|
}
|
|
for _, key := range []string{"actressIds", "tags"} {
|
|
value, ok := raw[key]
|
|
if !ok {
|
|
continue
|
|
}
|
|
next, keep, err := normalizeIntSliceRaw(value)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s %w", key, err)
|
|
}
|
|
if !keep {
|
|
continue
|
|
}
|
|
if next == nil {
|
|
delete(raw, key)
|
|
continue
|
|
}
|
|
raw[key] = next
|
|
}
|
|
if value, ok := raw["categoryRanks"]; ok {
|
|
next, keep, err := normalizeCategoryRanksRaw(value, raw["categoryId"])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !keep {
|
|
delete(raw, "categoryRanks")
|
|
} else {
|
|
raw["categoryRanks"] = next
|
|
}
|
|
}
|
|
return json.Marshal(raw)
|
|
}
|
|
|
|
func normalizeTimeRaw(raw json.RawMessage) (json.RawMessage, error) {
|
|
raw = bytes.TrimSpace(raw)
|
|
if len(raw) == 0 || bytes.Equal(raw, []byte("null")) {
|
|
return raw, nil
|
|
}
|
|
var text string
|
|
if err := json.Unmarshal(raw, &text); err != nil {
|
|
return nil, fmt.Errorf("时间格式错误")
|
|
}
|
|
text = strings.TrimSpace(text)
|
|
if text == "" {
|
|
return nil, nil
|
|
}
|
|
parsed, err := parseFlexTime(text)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return json.Marshal(parsed)
|
|
}
|
|
|
|
func parseFlexTime(text string) (time.Time, error) {
|
|
if parsed, err := time.Parse(time.RFC3339Nano, text); err == nil {
|
|
return parsed, nil
|
|
}
|
|
if parsed, err := time.Parse(time.RFC3339, text); err == nil {
|
|
return parsed, nil
|
|
}
|
|
for _, layout := range []string{"2006-01-02 15:04:05", "2006-01-02T15:04:05", "2006-01-02"} {
|
|
if parsed, err := time.ParseInLocation(layout, text, time.Local); err == nil {
|
|
return parsed, nil
|
|
}
|
|
}
|
|
return time.Time{}, fmt.Errorf("时间格式错误: %s", text)
|
|
}
|
|
|
|
// normalizeIntRaw 把数字或数字字符串整理成 JSON 数字。空字符串表示删除该字段。
|
|
func normalizeIntRaw(raw json.RawMessage) (json.RawMessage, bool, error) {
|
|
raw = bytes.TrimSpace(raw)
|
|
if len(raw) == 0 {
|
|
return nil, false, nil
|
|
}
|
|
if bytes.Equal(raw, []byte("null")) {
|
|
return raw, true, nil
|
|
}
|
|
if raw[0] != '"' {
|
|
var number json.Number
|
|
if err := json.Unmarshal(raw, &number); err != nil {
|
|
return nil, false, fmt.Errorf("数字格式错误")
|
|
}
|
|
if _, err := number.Int64(); err != nil {
|
|
return nil, false, fmt.Errorf("数字格式错误")
|
|
}
|
|
return raw, true, nil
|
|
}
|
|
var text string
|
|
if err := json.Unmarshal(raw, &text); err != nil {
|
|
return nil, false, fmt.Errorf("数字格式错误")
|
|
}
|
|
text = strings.TrimSpace(text)
|
|
if text == "" {
|
|
return nil, true, nil
|
|
}
|
|
value, err := strconv.ParseInt(text, 10, 64)
|
|
if err != nil {
|
|
return nil, false, fmt.Errorf("数字格式错误: %s", text)
|
|
}
|
|
encoded, err := json.Marshal(value)
|
|
return encoded, true, err
|
|
}
|
|
|
|
func normalizeIntSliceRaw(raw json.RawMessage) (json.RawMessage, bool, error) {
|
|
raw = bytes.TrimSpace(raw)
|
|
if len(raw) == 0 || bytes.Equal(raw, []byte("null")) {
|
|
return raw, true, nil
|
|
}
|
|
if bytes.Equal(raw, []byte(`""`)) {
|
|
return nil, true, nil
|
|
}
|
|
if raw[0] != '[' {
|
|
return nil, false, fmt.Errorf("数组格式错误")
|
|
}
|
|
var items []json.RawMessage
|
|
if err := json.Unmarshal(raw, &items); err != nil {
|
|
return nil, false, err
|
|
}
|
|
values := make([]int64, 0, len(items))
|
|
for _, item := range items {
|
|
next, keep, err := normalizeIntRaw(item)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if !keep || next == nil || bytes.Equal(bytes.TrimSpace(next), []byte("null")) {
|
|
return nil, false, fmt.Errorf("数字格式错误")
|
|
}
|
|
var value int64
|
|
if err := json.Unmarshal(next, &value); err != nil {
|
|
return nil, false, err
|
|
}
|
|
values = append(values, value)
|
|
}
|
|
encoded, err := json.Marshal(values)
|
|
return encoded, true, err
|
|
}
|
|
|
|
func normalizeCategoryRanksRaw(raw, categoryIDRaw json.RawMessage) (json.RawMessage, bool, error) {
|
|
raw = bytes.TrimSpace(raw)
|
|
if len(raw) == 0 || bytes.Equal(raw, []byte("null")) || bytes.Equal(raw, []byte(`""`)) {
|
|
return nil, false, nil
|
|
}
|
|
fallbackID := int64FromRaw(categoryIDRaw)
|
|
if raw[0] != '[' {
|
|
item, ok, err := normalizeCategoryRankItem(raw, fallbackID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if !ok {
|
|
return nil, false, nil
|
|
}
|
|
encoded, err := json.Marshal([]categoryRankJSON{item})
|
|
return encoded, true, err
|
|
}
|
|
var items []json.RawMessage
|
|
if err := json.Unmarshal(raw, &items); err != nil {
|
|
return nil, false, fmt.Errorf("分类排序格式错误")
|
|
}
|
|
if len(items) == 0 {
|
|
encoded, err := json.Marshal([]categoryRankJSON{})
|
|
return encoded, true, err
|
|
}
|
|
cleaned := make([]categoryRankJSON, 0, len(items))
|
|
for _, item := range items {
|
|
rank, ok, err := normalizeCategoryRankItem(item, fallbackID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if !ok {
|
|
continue
|
|
}
|
|
cleaned = append(cleaned, rank)
|
|
}
|
|
if len(cleaned) == 0 {
|
|
return nil, false, nil
|
|
}
|
|
encoded, err := json.Marshal(cleaned)
|
|
return encoded, true, err
|
|
}
|
|
|
|
type categoryRankJSON struct {
|
|
Id int64 `json:"id"`
|
|
Rank int64 `json:"rank"`
|
|
}
|
|
|
|
func normalizeCategoryRankItem(raw json.RawMessage, fallbackID int64) (categoryRankJSON, bool, error) {
|
|
raw = bytes.TrimSpace(raw)
|
|
if len(raw) == 0 || bytes.Equal(raw, []byte("null")) {
|
|
return categoryRankJSON{}, false, nil
|
|
}
|
|
if raw[0] != '{' {
|
|
if bytes.Equal(raw, []byte("null")) || bytes.Equal(raw, []byte(`""`)) || rawIsZero(raw) {
|
|
return categoryRankJSON{}, false, nil
|
|
}
|
|
rank := int64FromRaw(raw)
|
|
if rank == 0 {
|
|
return categoryRankJSON{}, false, fmt.Errorf("分类排序格式错误")
|
|
}
|
|
if fallbackID <= 0 {
|
|
return categoryRankJSON{}, false, fmt.Errorf("分类排序缺少分类ID")
|
|
}
|
|
return categoryRankJSON{Id: fallbackID, Rank: rank}, true, nil
|
|
}
|
|
var fields map[string]json.RawMessage
|
|
if err := json.Unmarshal(raw, &fields); err != nil {
|
|
return categoryRankJSON{}, false, fmt.Errorf("分类排序格式错误")
|
|
}
|
|
id := int64FromRaw(fields["id"])
|
|
if id <= 0 {
|
|
id = int64FromRaw(fields["categoryId"])
|
|
}
|
|
rank := int64FromRaw(fields["rank"])
|
|
if id <= 0 && !rawHasValue(fields["rank"]) {
|
|
return categoryRankJSON{}, false, nil
|
|
}
|
|
if id <= 0 {
|
|
id = fallbackID
|
|
}
|
|
if id <= 0 {
|
|
return categoryRankJSON{}, false, fmt.Errorf("分类排序缺少分类ID")
|
|
}
|
|
return categoryRankJSON{Id: id, Rank: rank}, true, nil
|
|
}
|
|
|
|
func rawHasValue(raw json.RawMessage) bool {
|
|
raw = bytes.TrimSpace(raw)
|
|
return len(raw) > 0 && !bytes.Equal(raw, []byte("null")) && !bytes.Equal(raw, []byte(`""`))
|
|
}
|
|
|
|
func int64FromRaw(raw json.RawMessage) int64 {
|
|
next, keep, err := normalizeIntRaw(raw)
|
|
if err != nil || !keep || next == nil || bytes.Equal(bytes.TrimSpace(next), []byte("null")) {
|
|
return 0
|
|
}
|
|
var value int64
|
|
if err := json.Unmarshal(next, &value); err != nil {
|
|
return 0
|
|
}
|
|
return value
|
|
}
|
|
|
|
func rawIsZero(raw json.RawMessage) bool {
|
|
next, keep, err := normalizeIntRaw(raw)
|
|
return err == nil && keep && bytes.Equal(bytes.TrimSpace(next), []byte("0"))
|
|
}
|