mirror of
https://github.com/ProudMuBai/GoFilm.git
synced 2026-02-13 05:24:41 +08:00
321 lines
11 KiB
Go
321 lines
11 KiB
Go
package system
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/redis/go-redis/v9"
|
||
"hash/fnv"
|
||
"regexp"
|
||
"server/config"
|
||
"server/plugin/db"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// Movie 影片基本信息
|
||
type Movie struct {
|
||
Id int64 `json:"id"` // 影片ID
|
||
Name string `json:"name"` // 影片名
|
||
Cid int64 `json:"cid"` // 所属分类ID
|
||
CName string `json:"CName"` // 所属分类名称
|
||
EnName string `json:"enName"` // 英文片名
|
||
Time string `json:"time"` // 更新时间
|
||
Remarks string `json:"remarks"` // 备注 | 清晰度
|
||
PlayFrom string `json:"playFrom"` // 播放来源
|
||
}
|
||
|
||
// MovieDescriptor 影片详情介绍信息
|
||
type MovieDescriptor struct {
|
||
SubTitle string `json:"subTitle"` //子标题
|
||
CName string `json:"cName"` //分类名称
|
||
EnName string `json:"enName"` //英文名
|
||
Initial string `json:"initial"` //首字母
|
||
ClassTag string `json:"classTag"` //分类标签
|
||
Actor string `json:"actor"` //主演
|
||
Director string `json:"director"` //导演
|
||
Writer string `json:"writer"` //作者
|
||
Blurb string `json:"blurb"` //简介, 残缺,不建议使用
|
||
Remarks string `json:"remarks"` // 更新情况
|
||
ReleaseDate string `json:"releaseDate"` //上映时间
|
||
Area string `json:"area"` // 地区
|
||
Language string `json:"language"` //语言
|
||
Year string `json:"year"` //年份
|
||
State string `json:"state"` //影片状态 正片|预告...
|
||
UpdateTime string `json:"updateTime"` //更新时间
|
||
AddTime int64 `json:"addTime"` //资源添加时间戳
|
||
DbId int64 `json:"dbId"` //豆瓣id
|
||
DbScore string `json:"dbScore"` // 豆瓣评分
|
||
Hits int64 `json:"hits"` //影片热度
|
||
Content string `json:"content"` //内容简介
|
||
}
|
||
|
||
// MovieBasicInfo 影片基本信息
|
||
type MovieBasicInfo struct {
|
||
Id int64 `json:"id"` //影片Id
|
||
Cid int64 `json:"cid"` //分类ID
|
||
Pid int64 `json:"pid"` //一级分类ID
|
||
Name string `json:"name"` //片名
|
||
SubTitle string `json:"subTitle"` //子标题
|
||
CName string `json:"cName"` //分类名称
|
||
State string `json:"state"` //影片状态 正片|预告...
|
||
Picture string `json:"picture"` //简介图片
|
||
Actor string `json:"actor"` //主演
|
||
Director string `json:"director"` //导演
|
||
Blurb string `json:"blurb"` //简介, 不完整
|
||
Remarks string `json:"remarks"` // 更新情况
|
||
Area string `json:"area"` // 地区
|
||
Year string `json:"year"` //年份
|
||
}
|
||
|
||
// MovieUrlInfo 影视资源url信息
|
||
type MovieUrlInfo struct {
|
||
Episode string `json:"episode"` // 集数
|
||
Link string `json:"link"` // 播放地址
|
||
}
|
||
|
||
// MovieDetail 影片详情信息
|
||
type MovieDetail struct {
|
||
Id int64 `json:"id"` //影片Id
|
||
Cid int64 `json:"cid"` //分类ID
|
||
Pid int64 `json:"pid"` //一级分类ID
|
||
Name string `json:"name"` //片名
|
||
Picture string `json:"picture"` //简介图片
|
||
PlayFrom []string `json:"playFrom"` // 播放来源
|
||
DownFrom string `json:"DownFrom"` //下载来源 例: http
|
||
//PlaySeparator string `json:"playSeparator"` // 播放信息分隔符
|
||
PlayList [][]MovieUrlInfo `json:"playList"` //播放地址url
|
||
DownloadList [][]MovieUrlInfo `json:"downloadList"` // 下载url地址
|
||
MovieDescriptor `json:"descriptor"` //影片描述信息
|
||
}
|
||
|
||
// ===================================Redis数据交互========================================================
|
||
|
||
// SaveDetails 保存影片详情信息到redis中 格式: MovieDetail:Cid?:Id?
|
||
func SaveDetails(list []MovieDetail) (err error) {
|
||
// 遍历list中的信息
|
||
for _, detail := range list {
|
||
// 序列化影片详情信息
|
||
data, _ := json.Marshal(detail)
|
||
// 1. 原使用Zset存储, 但是不便于单个检索 db.Rdb.ZAdd(db.Cxt, fmt.Sprintf("%s:Cid%d", config.MovieDetailKey, detail.Cid), redis.Z{Score: float64(detail.Id), Member: member}).Err()
|
||
// 改为普通 k v 存储, k-> id关键字, v json序列化的结果
|
||
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
|
||
// 2. 同步保存简略信息到redis中
|
||
SaveMovieBasicInfo(detail)
|
||
// 3. 保存 Search tag redis中
|
||
if err == nil {
|
||
// 转换 detail信息
|
||
searchInfo := ConvertSearchInfo(detail)
|
||
// 只存储用于检索对应影片的关键字信息
|
||
SaveSearchTag(searchInfo)
|
||
}
|
||
|
||
}
|
||
// 保存一份search信息到mysql, 批量存储
|
||
BatchSaveSearchInfo(list)
|
||
return err
|
||
}
|
||
|
||
// SaveDetail 保存单部影片信息
|
||
func SaveDetail(detail MovieDetail) (err error) {
|
||
// 序列化影片详情信息
|
||
data, _ := json.Marshal(detail)
|
||
// 保存影片信息到Redis
|
||
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// 2. 同步保存简略信息到redis中
|
||
SaveMovieBasicInfo(detail)
|
||
// 转换 detail信息
|
||
searchInfo := ConvertSearchInfo(detail)
|
||
// 3. 保存 Search tag redis中
|
||
// 只存储用于检索对应影片的关键字信息
|
||
SaveSearchTag(searchInfo)
|
||
// 保存影片检索信息到searchTable
|
||
err = SaveSearchInfo(searchInfo)
|
||
return err
|
||
}
|
||
|
||
// SaveMovieBasicInfo 摘取影片的详情部分信息转存为影视基本信息
|
||
func SaveMovieBasicInfo(detail MovieDetail) {
|
||
basicInfo := MovieBasicInfo{
|
||
Id: detail.Id,
|
||
Cid: detail.Cid,
|
||
Pid: detail.Pid,
|
||
Name: detail.Name,
|
||
SubTitle: detail.SubTitle,
|
||
CName: detail.CName,
|
||
State: detail.State,
|
||
Picture: detail.Picture,
|
||
Actor: detail.Actor,
|
||
Director: detail.Director,
|
||
Blurb: detail.Blurb,
|
||
Remarks: detail.Remarks,
|
||
Area: detail.Area,
|
||
Year: detail.Year,
|
||
}
|
||
data, _ := json.Marshal(basicInfo)
|
||
_ = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieBasicInfoKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
|
||
}
|
||
|
||
// SaveSitePlayList 仅保存播放url列表信息到当前站点
|
||
func SaveSitePlayList(id string, list []MovieDetail) (err error) {
|
||
// 如果list 为空则直接返回
|
||
if len(list) <= 0 {
|
||
return nil
|
||
}
|
||
res := make(map[string]string)
|
||
for _, d := range list {
|
||
if len(d.PlayList) > 0 {
|
||
data, _ := json.Marshal(d.PlayList[0])
|
||
// 不保存电影解说类
|
||
if strings.Contains(d.CName, "解说") {
|
||
continue
|
||
}
|
||
// 如果DbId不为0, 则以dbID作为key进行hash额外存储一次
|
||
if d.DbId != 0 {
|
||
res[GenerateHashKey(d.DbId)] = string(data)
|
||
}
|
||
res[GenerateHashKey(d.Name)] = string(data)
|
||
}
|
||
}
|
||
// 如果结果不为空,则将数据保存到redis中
|
||
if len(res) > 0 {
|
||
// 保存形式 key: MultipleSource:siteName Hash[hash(movieName)]list
|
||
err = db.Rdb.HMSet(db.Cxt, fmt.Sprintf(config.MultipleSiteDetail, id), res).Err()
|
||
}
|
||
return
|
||
}
|
||
|
||
// BatchSaveSearchInfo 批量保存Search信息
|
||
func BatchSaveSearchInfo(list []MovieDetail) {
|
||
var infoList []SearchInfo
|
||
for _, v := range list {
|
||
infoList = append(infoList, ConvertSearchInfo(v))
|
||
}
|
||
// 将检索信息存入redis中做一次转存
|
||
RdbSaveSearchInfo(infoList)
|
||
}
|
||
|
||
// ConvertSearchInfo 将detail信息处理成 searchInfo
|
||
func ConvertSearchInfo(detail MovieDetail) SearchInfo {
|
||
score, _ := strconv.ParseFloat(detail.DbScore, 64)
|
||
stamp, _ := time.ParseInLocation(time.DateTime, detail.UpdateTime, time.Local)
|
||
// detail中的年份信息并不准确, 因此采用 ReleaseDate中的年份
|
||
year, err := strconv.ParseInt(regexp.MustCompile(`[1-9][0-9]{3}`).FindString(detail.ReleaseDate), 10, 64)
|
||
if err != nil {
|
||
year = 0
|
||
}
|
||
return SearchInfo{
|
||
Mid: detail.Id,
|
||
Cid: detail.Cid,
|
||
Pid: detail.Pid,
|
||
Name: detail.Name,
|
||
SubTitle: detail.SubTitle,
|
||
CName: detail.CName,
|
||
ClassTag: detail.ClassTag,
|
||
Area: detail.Area,
|
||
Language: detail.Language,
|
||
Year: year,
|
||
Initial: detail.Initial,
|
||
Score: score,
|
||
Hits: detail.Hits,
|
||
UpdateStamp: stamp.Unix(),
|
||
State: detail.State,
|
||
Remarks: detail.Remarks,
|
||
// ReleaseDate 部分影片缺失该参数, 所以使用添加时间作为上映时间排序
|
||
ReleaseStamp: detail.AddTime,
|
||
}
|
||
}
|
||
|
||
// GetBasicInfoByKey 获取Id对应的影片基本信息
|
||
func GetBasicInfoByKey(key string) MovieBasicInfo {
|
||
// 反序列化得到的结果
|
||
data := []byte(db.Rdb.Get(db.Cxt, key).Val())
|
||
basic := MovieBasicInfo{}
|
||
_ = json.Unmarshal(data, &basic)
|
||
// 执行本地图片匹配
|
||
ReplaceBasicDetailPic(&basic)
|
||
return basic
|
||
}
|
||
|
||
// GetDetailByKey 获取影片对应的详情信息
|
||
func GetDetailByKey(key string) MovieDetail {
|
||
// 反序列化得到的结果
|
||
data := []byte(db.Rdb.Get(db.Cxt, key).Val())
|
||
detail := MovieDetail{}
|
||
_ = json.Unmarshal(data, &detail)
|
||
|
||
// 执行本地图片匹配
|
||
ReplaceDetailPic(&detail)
|
||
return detail
|
||
}
|
||
|
||
// GetBasicInfoBySearchInfos 通过searchInfo 获取影片的基本信息
|
||
func GetBasicInfoBySearchInfos(infos ...SearchInfo) []MovieBasicInfo {
|
||
var list []MovieBasicInfo
|
||
for _, s := range infos {
|
||
data := []byte(db.Rdb.Get(db.Cxt, fmt.Sprintf(config.MovieBasicInfoKey, s.Cid, s.Mid)).Val())
|
||
basic := MovieBasicInfo{}
|
||
_ = json.Unmarshal(data, &basic)
|
||
|
||
// 执行本地图片匹配
|
||
ReplaceBasicDetailPic(&basic)
|
||
list = append(list, basic)
|
||
}
|
||
return list
|
||
}
|
||
|
||
/*
|
||
对附属播放源入库时的name|dbID进行处理,保证唯一性
|
||
1. 去除name中的所有空格
|
||
2. 去除name中含有的别名~.*~
|
||
3. 去除name首尾的标点符号
|
||
4. 将处理完成后的name转化为hash值作为存储时的key
|
||
*/
|
||
// GenerateHashKey 存储播放源信息时对影片名称进行处理, 提高各站点间同一影片的匹配度
|
||
func GenerateHashKey[K string | ~int | int64](key K) string {
|
||
mName := fmt.Sprint(key)
|
||
//1. 去除name中的所有空格
|
||
mName = regexp.MustCompile(`\s`).ReplaceAllString(mName, "")
|
||
//2. 去除name中含有的别名~.*~
|
||
mName = regexp.MustCompile(`~.*~$`).ReplaceAllString(mName, "")
|
||
//3. 去除name首尾的标点符号
|
||
mName = regexp.MustCompile(`^[[:punct:]]+|[[:punct:]]+$`).ReplaceAllString(mName, "")
|
||
// 部分站点包含 动画版, 特殊别名 等字符, 需进行删除
|
||
//mName = regexp.MustCompile(`动画版`).ReplaceAllString(mName, "")
|
||
mName = regexp.MustCompile(`季.*`).ReplaceAllString(mName, "季")
|
||
//4. 将处理完成后的name转化为hash值作为存储时的key
|
||
h := fnv.New32a()
|
||
_, err := h.Write([]byte(mName))
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
return fmt.Sprint(h.Sum32())
|
||
}
|
||
|
||
// ============================采集方案.v1 遗留==================================================
|
||
|
||
// SaveMoves 保存影片分页请求list
|
||
func SaveMoves(list []Movie) (err error) {
|
||
// 整合数据
|
||
for _, m := range list {
|
||
//score, _ := time.ParseInLocation(time.DateTime, m.Time, time.Local)
|
||
movie, _ := json.Marshal(m)
|
||
// 以Cid为目录为集合进行存储, 便于后续搜索, 以影片id为分值进行存储 例 MovieList:Cid%d
|
||
err = db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.MovieListInfoKey, m.Cid), redis.Z{Score: float64(m.Id), Member: movie}).Err()
|
||
}
|
||
return err
|
||
}
|
||
|
||
// AllMovieInfoKey 获取redis中所有的影视列表信息key MovieList:Cid
|
||
func AllMovieInfoKey() []string {
|
||
return db.Rdb.Keys(db.Cxt, fmt.Sprint("MovieList:Cid*")).Val()
|
||
}
|
||
|
||
// GetMovieListByKey 获取指定分类的影片列表数据
|
||
func GetMovieListByKey(key string) []string {
|
||
return db.Rdb.ZRange(db.Cxt, key, 0, -1).Val()
|
||
}
|