mirror of
https://github.com/iLoveElysia/openbilibili.git
synced 2026-06-07 21:48:31 -05:00
245 lines
5.4 KiB
Go
245 lines
5.4 KiB
Go
|
|
package model
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"bytes"
|
|||
|
|
"crypto/md5"
|
|||
|
|
"encoding/json"
|
|||
|
|
"fmt"
|
|||
|
|
"math"
|
|||
|
|
"net/url"
|
|||
|
|
"strconv"
|
|||
|
|
"strings"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"go-common/library/log"
|
|||
|
|
|
|||
|
|
"github.com/dgryski/go-farm"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// SplitInts splts string to int-slice by ,
|
|||
|
|
func SplitInts(s string) (res []int) {
|
|||
|
|
if s == "" {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
ints := strings.Split(s, ",")
|
|||
|
|
for _, v := range ints {
|
|||
|
|
i, _ := strconv.Atoi(v)
|
|||
|
|
res = append(res, i)
|
|||
|
|
}
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// JoinInts merges int slice to string.
|
|||
|
|
func JoinInts(ints []int) string {
|
|||
|
|
if len(ints) == 0 {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
if len(ints) == 1 {
|
|||
|
|
return strconv.Itoa(ints[0])
|
|||
|
|
}
|
|||
|
|
buf := bytes.Buffer{}
|
|||
|
|
for _, v := range ints {
|
|||
|
|
buf.WriteString(strconv.Itoa(v))
|
|||
|
|
buf.WriteString(",")
|
|||
|
|
}
|
|||
|
|
if buf.Len() > 0 {
|
|||
|
|
buf.Truncate(buf.Len() - 1)
|
|||
|
|
}
|
|||
|
|
return buf.String()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ExistsInt judge if item in the ints.
|
|||
|
|
func ExistsInt(ints []int, item int) (exists bool) {
|
|||
|
|
for _, i := range ints {
|
|||
|
|
if i == item {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HashToken gets token's hash value.
|
|||
|
|
func HashToken(token string) int64 {
|
|||
|
|
return int64(farm.Hash64([]byte(token)) % math.MaxInt64)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RealTime culculates real time by timezone.
|
|||
|
|
func RealTime(reportZone int) time.Time {
|
|||
|
|
now := time.Now()
|
|||
|
|
_, offset := now.Zone()
|
|||
|
|
return now.Add(time.Duration(reportZone-offset/3600) * time.Hour)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Scheme gets uri scheme.
|
|||
|
|
func Scheme(typ int8, val string, platform, build int) (uri string) {
|
|||
|
|
switch typ {
|
|||
|
|
case LinkTypeBangumi: // 番剧
|
|||
|
|
if platform == PlatformAndroid {
|
|||
|
|
uri = SchemeBangumiSeasonAndroid + val
|
|||
|
|
} else {
|
|||
|
|
uri = SchemeBangumiSeasonIOS + val
|
|||
|
|
}
|
|||
|
|
case LinkTypeVideo: // 视频
|
|||
|
|
if platform == PlatformAndroid {
|
|||
|
|
uri = SchemeVideoAndroid + val
|
|||
|
|
} else {
|
|||
|
|
uri = SchemeVideoIOS + val
|
|||
|
|
}
|
|||
|
|
case LinkTypeLive:
|
|||
|
|
var (
|
|||
|
|
param string
|
|||
|
|
parts = strings.Split(val, ",") // 值可能为 1 或者 1,0
|
|||
|
|
)
|
|||
|
|
if len(parts) == 2 {
|
|||
|
|
param = "?broadcast_type=" + parts[1]
|
|||
|
|
}
|
|||
|
|
uri = SchemeLive + parts[0] + param
|
|||
|
|
if platform == PlatformAndroid && build < 5290000 {
|
|||
|
|
uri = SchemeLiveAndroid + parts[0]
|
|||
|
|
}
|
|||
|
|
case LinkTypeSplist: // 专题
|
|||
|
|
uri = SchemeSplist + val
|
|||
|
|
case LinkTypeAuthor: // 个人空间
|
|||
|
|
if platform == PlatformAndroid {
|
|||
|
|
uri = SchemeAuthorAndroid + val
|
|||
|
|
} else {
|
|||
|
|
uri = SchemeAuthorIOS + val
|
|||
|
|
}
|
|||
|
|
case LinkTypeSearch: // 搜索
|
|||
|
|
if platform == PlatformAndroid {
|
|||
|
|
uri = SchemeSearchAndroid + val
|
|||
|
|
} else {
|
|||
|
|
uri = SchemeSearchIOS + val
|
|||
|
|
}
|
|||
|
|
case LinkTypeBrowser: // H5
|
|||
|
|
if platform == PlatformAndroid {
|
|||
|
|
uri = SchemeBrowserAndroid + url.QueryEscape(val)
|
|||
|
|
} else {
|
|||
|
|
// 容错逻辑,标准写法是 SchemeBrowserIOS + val,且 val 需要业务方进行 urlencode
|
|||
|
|
// 但是老客户端有bug,客户端会强制encode,客户端从 5.28 开始修了这个bug
|
|||
|
|
// 版本覆盖完全后,可改成标准写法
|
|||
|
|
uri = val
|
|||
|
|
}
|
|||
|
|
case LinkTypeVipBuy:
|
|||
|
|
uri = SchemeVipBuy + val
|
|||
|
|
case LinkTypeCustom:
|
|||
|
|
uri = val
|
|||
|
|
default:
|
|||
|
|
uri = ""
|
|||
|
|
}
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ParseBuild parses string to build struct.
|
|||
|
|
func ParseBuild(s string) (builds map[int]*Build) {
|
|||
|
|
builds = make(map[int]*Build)
|
|||
|
|
if s == "" {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
temp := make(map[string]*Build)
|
|||
|
|
if err := json.Unmarshal([]byte(s), &temp); err != nil {
|
|||
|
|
log.Error("json.Unmarshal(%s) error(%v)", s, err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
for plat, build := range temp {
|
|||
|
|
p, _ := strconv.Atoi(plat)
|
|||
|
|
builds[p] = build
|
|||
|
|
}
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TempTaskID gen temporary task ID.
|
|||
|
|
func TempTaskID() string {
|
|||
|
|
n := time.Now().UnixNano()
|
|||
|
|
m := md5.Sum([]byte(strconv.FormatInt(n, 10)))
|
|||
|
|
return TempTaskPrefix + fmt.Sprintf("%x", m)[:8] // 要把taskid当作jobkey参数,jobkey要求长度最多9位, 1位prefix+8位时间hash值前段
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// JobName gen job name.
|
|||
|
|
func JobName(timestamp int64, content, linkValue, group string) int64 {
|
|||
|
|
s := []byte(fmt.Sprintf("%d%s%s%s%s", timestamp, time.Now().Format("20060102"), content, linkValue, group))
|
|||
|
|
return int64(farm.Hash64(s) % math.MaxInt64)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Hash gen hash value by solt.
|
|||
|
|
func Hash(salt string) string {
|
|||
|
|
s := salt + strconv.FormatInt(time.Now().UnixNano(), 10)
|
|||
|
|
return fmt.Sprintf("%x", md5.Sum([]byte(s)))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 免打扰时间默认值
|
|||
|
|
const (
|
|||
|
|
_defaultSilentBeginHour = 22
|
|||
|
|
_defaultSilentEndHour = 8
|
|||
|
|
_defaultSilentBeginMinute = 0
|
|||
|
|
_defaultSilentEndMinute = 0
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ParseSilentTime .
|
|||
|
|
func ParseSilentTime(s string) (st BusinessSilentTime) {
|
|||
|
|
st = BusinessSilentTime{
|
|||
|
|
BeginHour: _defaultSilentBeginHour,
|
|||
|
|
EndHour: _defaultSilentEndHour,
|
|||
|
|
BeginMinute: _defaultSilentBeginMinute,
|
|||
|
|
EndMinute: _defaultSilentEndMinute,
|
|||
|
|
}
|
|||
|
|
s = strings.Trim(s, " ")
|
|||
|
|
if s == "" {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r := strings.Split(s, "-")
|
|||
|
|
if len(r) != 2 {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
begin := strings.Split(r[0], ":")
|
|||
|
|
if len(begin) == 2 {
|
|||
|
|
st.BeginHour, _ = strconv.Atoi(begin[0])
|
|||
|
|
st.BeginMinute, _ = strconv.Atoi(begin[1])
|
|||
|
|
}
|
|||
|
|
end := strings.Split(r[1], ":")
|
|||
|
|
if len(end) == 2 {
|
|||
|
|
st.EndHour, _ = strconv.Atoi(end[0])
|
|||
|
|
st.EndMinute, _ = strconv.Atoi(end[1])
|
|||
|
|
}
|
|||
|
|
return st
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsAndroid .
|
|||
|
|
func IsAndroid(platformID int) bool {
|
|||
|
|
m := map[int]bool{
|
|||
|
|
PlatformIPhone: true,
|
|||
|
|
PlatformIPad: true,
|
|||
|
|
}
|
|||
|
|
return !m[platformID]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateBuild checks token&platform valid.
|
|||
|
|
func ValidateBuild(platform, build int, builds map[int]*Build) bool {
|
|||
|
|
if len(builds) == 0 {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
if IsAndroid(platform) {
|
|||
|
|
platform = PlatformAndroid
|
|||
|
|
}
|
|||
|
|
if builds[platform] == nil {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
c := builds[platform].Condition
|
|||
|
|
b := builds[platform].Build
|
|||
|
|
switch c {
|
|||
|
|
case "gt":
|
|||
|
|
return build > b
|
|||
|
|
case "gte":
|
|||
|
|
return build >= b
|
|||
|
|
case "lt":
|
|||
|
|
return build < b
|
|||
|
|
case "lte":
|
|||
|
|
return build <= b
|
|||
|
|
case "eq":
|
|||
|
|
return build == b
|
|||
|
|
case "ne":
|
|||
|
|
return build != b
|
|||
|
|
}
|
|||
|
|
return false
|
|||
|
|
}
|