فهرست منبع

备份进度

Signed-off-by: allan716 <[email protected]>
allan716 3 سال پیش
والد
کامیت
a2810cb3ad

+ 3 - 0
go.mod

@@ -78,6 +78,7 @@ require (
 	github.com/bodgit/windows v1.0.0 // indirect
 	github.com/connesc/cipherio v0.2.1 // indirect
 	github.com/dsnet/compress v0.0.1 // indirect
+	github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-git/gcfg v1.5.0 // indirect
 	github.com/go-git/go-billy/v5 v5.3.1 // indirect
@@ -119,6 +120,8 @@ require (
 	go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
 	golang.org/x/exp v0.0.0-20211123021643-48cbe7f80d7c // indirect
 	google.golang.org/protobuf v1.27.1 // indirect
+	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
+	gopkg.in/mail.v2 v2.3.1 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 )
 

+ 12 - 0
go.sum

@@ -130,6 +130,14 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/emersion/go-imap v1.2.0 h1:lyUQ3+EVM21/qbWE/4Ya5UG9r5+usDxlg4yfp3TgHFA=
+github.com/emersion/go-imap v1.2.0/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
+github.com/emersion/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:43mBoVwooyLm1+1YVf5nvn1pSFWhw7rOpcrp1Jg/qk0=
+github.com/emersion/go-imap-id v0.0.0-20190926060100-f94a56b9ecde/go.mod h1:sPwp0FFboaK/bxsrUz1lNrDMUCsZUsKC5YuM4uRVRVs=
+github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
+github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
+github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
+github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
 github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
 github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
@@ -886,6 +894,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -902,6 +912,8 @@ gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWd
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
 gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
+gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=

+ 2 - 1
internal/dao/init.go

@@ -66,7 +66,8 @@ func InitDb() error {
 		return errors.New(fmt.Sprintf("failed to connect database, %s", err.Error()))
 	}
 	// 迁移 schema
-	err = db.AutoMigrate(&models.HotFix{}, &models.SubFormatRec{})
+	err = db.AutoMigrate(&models.HotFix{}, &models.SubFormatRec{},
+		&models.IMDBInfo{}, &models.VideoSubInfo{})
 	if err != nil {
 		return errors.New(fmt.Sprintf("db AutoMigrate error, %s", err.Error()))
 	}

+ 6 - 6
internal/logic/series_helper/seriesHelper.go

@@ -2,11 +2,11 @@ package series_helper
 
 import (
 	"fmt"
-	"github.com/StalkR/imdb"
 	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
+	"github.com/allanpk716/ChineseSubFinder/internal/models"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/imdb_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
@@ -25,7 +25,7 @@ import (
 )
 
 // ReadSeriesInfoFromDir 读取剧集的信息,只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList
-func ReadSeriesInfoFromDir(seriesDir string, imdbInfo *imdb.Title, forcedScanAndDownloadSub bool) (*series.SeriesInfo, error) {
+func ReadSeriesInfoFromDir(seriesDir string, imdbInfo *models.IMDBInfo, forcedScanAndDownloadSub bool) (*series.SeriesInfo, error) {
 
 	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
 
@@ -97,7 +97,7 @@ func ReadSeriesInfoFromDir(seriesDir string, imdbInfo *imdb.Title, forcedScanAnd
 }
 
 // ReadSeriesInfoFromEmby 将 Emby API 读取到的数据进行转换到通用的结构中,需要填充那些剧集需要下载,这样要的是一个连续剧的,不是所有的传入
-func ReadSeriesInfoFromEmby(seriesDir string, imdbInfo *imdb.Title, seriesList []emby.EmbyMixInfo) (*series.SeriesInfo, error) {
+func ReadSeriesInfoFromEmby(seriesDir string, imdbInfo *models.IMDBInfo, seriesList []emby.EmbyMixInfo) (*series.SeriesInfo, error) {
 
 	seriesInfo, err := getSeriesInfoFromDir(seriesDir, imdbInfo)
 	if err != nil {
@@ -122,7 +122,7 @@ func ReadSeriesInfoFromEmby(seriesDir string, imdbInfo *imdb.Title, seriesList [
 }
 
 // SkipChineseSeries 跳过中文连续剧
-func SkipChineseSeries(seriesRootPath string, _proxySettings ...settings.ProxySettings) (bool, *imdb.Title, error) {
+func SkipChineseSeries(seriesRootPath string, _proxySettings ...settings.ProxySettings) (bool, *models.IMDBInfo, error) {
 	var proxySettings settings.ProxySettings
 	if len(_proxySettings) > 0 {
 		proxySettings = _proxySettings[0]
@@ -310,7 +310,7 @@ func whichSeasonEpsNeedDownloadSub(seriesInfo *series.SeriesInfo, forcedScanAndD
 	return needDlSubEpsList, needDlSeasonList
 }
 
-func getSeriesInfoFromDir(seriesDir string, imdbInfo *imdb.Title) (*series.SeriesInfo, error) {
+func getSeriesInfoFromDir(seriesDir string, imdbInfo *models.IMDBInfo) (*series.SeriesInfo, error) {
 	seriesInfo := series.SeriesInfo{}
 	// 只考虑 IMDB 去查询,文件名目前发现可能会跟电影重复,导致很麻烦,本来也有前置要求要削刮器处理的
 	videoInfo, err := decode.GetImdbInfo4SeriesDir(seriesDir)
@@ -321,7 +321,7 @@ func getSeriesInfoFromDir(seriesDir string, imdbInfo *imdb.Title) (*series.Serie
 	// 以 IMDB 的信息为准
 	if imdbInfo != nil {
 		seriesInfo.Name = imdbInfo.Name
-		seriesInfo.ImdbId = imdbInfo.ID
+		seriesInfo.ImdbId = imdbInfo.IMDBID
 		seriesInfo.Year = imdbInfo.Year
 	} else {
 		seriesInfo.Name = videoInfo.Title

+ 6 - 0
internal/models/imdb_aka.go

@@ -0,0 +1,6 @@
+package models
+
+type IMDBAKA struct {
+	AKA        string
+	IMDBInfoID uint
+}

+ 18 - 0
internal/models/imdb_info.go

@@ -0,0 +1,18 @@
+package models
+
+import "gorm.io/gorm"
+
+type IMDBInfo struct {
+	gorm.Model
+	IMDBID        string         `gorm:"primaryKey"` // IMDB ID
+	Name          string         // 视频名称
+	Year          int            `gorm:"default:0"` // 发布的时间
+	Description   string         // 描述
+	Languages     StringList     `gorm:"type:varchar(255);not null"`                     // 语言
+	AKA           StringList     `gorm:"type:varchar(255);not null"`                     // 又名 xx xxx
+	VideoSubInfos []VideoSubInfo `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` // 视频对应的字幕,外键约束
+}
+
+func NewIMDBInfo(IMDBID string, name string, year int, description string, languages StringList, AKA StringList) *IMDBInfo {
+	return &IMDBInfo{IMDBID: IMDBID, Name: name, Year: year, Description: description, Languages: languages, AKA: AKA, VideoSubInfos: make([]VideoSubInfo, 0)}
+}

+ 6 - 0
internal/models/imdb_language.go

@@ -0,0 +1,6 @@
+package models
+
+type IMDBLanguage struct {
+	Language   string
+	IMDBInfoID uint
+}

+ 16 - 0
internal/models/string_array.go

@@ -0,0 +1,16 @@
+package models
+
+import (
+	"database/sql/driver"
+	"encoding/json"
+)
+
+type StringList []string
+
+func (p StringList) Value() (driver.Value, error) {
+	return json.Marshal(p)
+}
+
+func (p *StringList) Scan(data interface{}) error {
+	return json.Unmarshal(data.([]byte), &p)
+}

+ 19 - 0
internal/models/video_sub_info.go

@@ -0,0 +1,19 @@
+package models
+
+import "gorm.io/gorm"
+
+// VideoSubInfo 属于 IMDBInfo,IMDBInfoID 是外键
+type VideoSubInfo struct {
+	gorm.Model
+	Feature     string `gorm:"primaryKey" json:"feature"` // 特征码,这个未必有,比如是蓝光格式,分散成多个视频文件的时候,暂定使用 shooter 的特征提前方式
+	SubName     string `json:"sub_name"`                  // 字幕的文件名
+	LanguageISO string `json:"language_iso"`              // 字幕的语言,目标语言,就算是双语,中英,也应该是中文。ISO_639-1_codes 标准,见 ISOLanguage.go 文件
+	IsDouble    bool   `json:"is_double"`                 // 是否是双语,上面是主体语言,比如是中文,
+	ChineseISO  string `json:"chinese_iso"`               // 中文语言编码变种,见 ISOLanguage.go 文件
+	MyLanguage  string `json:"my_language"`               // 这个是本程序定义的语言类型,见 my_language.go 文件
+	IMDBInfoID  uint
+}
+
+func NewVideoSubInfo(feature string, subName string, languageISO string, isDouble bool, chineseISO string, myLanguage string) *VideoSubInfo {
+	return &VideoSubInfo{Feature: feature, SubName: subName, LanguageISO: languageISO, IsDouble: isDouble, ChineseISO: chineseISO, MyLanguage: myLanguage}
+}

+ 34 - 10
internal/pkg/imdb_helper/imdb.go

@@ -2,6 +2,8 @@ package imdb_helper
 
 import (
 	"github.com/StalkR/imdb"
+	"github.com/allanpk716/ChineseSubFinder/internal/dao"
+	"github.com/allanpk716/ChineseSubFinder/internal/models"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
@@ -24,7 +26,7 @@ func GetVideoInfoFromIMDB(imdbID string, _proxySettings ...settings.ProxySetting
 }
 
 // IsChineseVideo 从 imdbID 去查询判断是否是中文视频
-func IsChineseVideo(imdbID string, _proxySettings ...settings.ProxySettings) (bool, *imdb.Title, error) {
+func IsChineseVideo(imdbID string, _proxySettings ...settings.ProxySettings) (bool, *models.IMDBInfo, error) {
 
 	const chName0 = "chinese"
 	const chName1 = "mandarin"
@@ -34,20 +36,42 @@ func IsChineseVideo(imdbID string, _proxySettings ...settings.ProxySettings) (bo
 		proxySettings = _proxySettings[0]
 	}
 
-	t, err := GetVideoInfoFromIMDB(imdbID, proxySettings)
-	if err != nil {
-		return false, nil, err
-	}
+	// 首先从数据库中查找是否存在这个 IMDB 信息,如果不存在再使用 Web 查找,且写入数据库
+	var imdbInfos []models.IMDBInfo
+	dao.GetDb().Limit(1).Where(&models.IMDBInfo{IMDBID: imdbID}).Find(&imdbInfos)
+
+	var firstLangLowCase string
+	if len(imdbInfos) <= 0 {
+		// 没有找到
+		t, err := GetVideoInfoFromIMDB(imdbID, proxySettings)
+		if err != nil {
+			return false, nil, err
+		}
+		// 存入数据库
+		nowIMDBInfo := models.NewIMDBInfo(imdbID, t.Name, t.Year, t.Description, t.Languages, t.AKA)
+		imdbInfos = make([]models.IMDBInfo, 0)
+		imdbInfos = append(imdbInfos, *nowIMDBInfo)
+		dao.GetDb().Create(nowIMDBInfo)
+
+		if len(t.Languages) <= 0 {
+			return false, nil, nil
+		}
+
+		firstLangLowCase = strings.ToLower(t.Languages[0])
+
+	} else {
+		// 找到
+		if len(imdbInfos[0].Languages) <= 0 {
+			return false, nil, nil
+		}
 
-	if len(t.Languages) <= 0 {
-		return false, nil, nil
+		firstLangLowCase = strings.ToLower(imdbInfos[0].Languages[0])
 	}
-	firstLangLowCase := strings.ToLower(t.Languages[0])
 	// 判断第一语言是否是中文
 	switch firstLangLowCase {
 	case chName0, chName1:
-		return true, t, nil
+		return true, &imdbInfos[0], nil
 	default:
-		return false, t, nil
+		return false, &imdbInfos[0], nil
 	}
 }

+ 21 - 0
internal/pkg/settings/sub_share_center.go

@@ -0,0 +1,21 @@
+package settings
+
+type SubShareCenter struct {
+	SenderSMTPAddress       string `json:"sender_smtp_address"`        // 发件人的 SMTP 服务地址和端口 outlook.office365.com:993
+	SenderSMTPPort          int    `json:"sender_smtp_port"`           // SMTP 的端口号
+	InsecureSkipVerify      bool   `json:"insecure_skip_verify"`       // 是否允许不安全连接
+	SenderEmailAddress      string `json:"sender_email_address"`       // 发件人的邮件地址
+	SenderEmailPwd          string `json:"sender_email_pwd"`           // 发件人的邮件地址对应的密码
+	ShareCenterEmailAddress string `json:"share_center_email_address"` // 收取邮件的目标邮件地址
+}
+
+func NewSubShareCenter(SenderSMTPAddress string, SenderSMTPPort int, InsecureSkipVerify bool, SenderEmailAddress, SenderEmailPwd, ShareCenterEmailAddress string) *SubShareCenter {
+	return &SubShareCenter{
+		SenderSMTPAddress,
+		SenderSMTPPort,
+		InsecureSkipVerify,
+		SenderEmailAddress,
+		SenderEmailPwd,
+		ShareCenterEmailAddress,
+	}
+}

+ 43 - 0
internal/pkg/sub_share_center/sub_share_center.go

@@ -0,0 +1,43 @@
+package sub_share_center
+
+import (
+	"crypto/tls"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	goMail "gopkg.in/mail.v2"
+)
+
+type SubShareCenter struct {
+	center settings.SubShareCenter
+	client *goMail.Dialer
+	dialer goMail.SendCloser
+}
+
+func NewSubShareCenter(center settings.SubShareCenter) *SubShareCenter {
+
+	nowClient := goMail.NewDialer(center.SenderSMTPAddress, center.SenderSMTPPort, center.SenderEmailAddress, center.SenderEmailPwd)
+	nowClient.TLSConfig = &tls.Config{InsecureSkipVerify: center.InsecureSkipVerify}
+	return &SubShareCenter{
+		center: center,
+		client: nowClient,
+	}
+}
+
+func (s *SubShareCenter) Login() error {
+
+	var err error
+	s.dialer, err = s.client.Dial()
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (s *SubShareCenter) Logout() error {
+	return s.dialer.Close()
+}
+
+func (s *SubShareCenter) SendSubtitle(imdbID, videoName, feature, subFIleFPath string) error {
+
+	return nil
+}