shooter.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package shooter
  2. import (
  3. "crypto/md5"
  4. "fmt"
  5. "github.com/allanpk716/ChineseSubFinder/internal/common"
  6. "github.com/allanpk716/ChineseSubFinder/internal/pkg"
  7. "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  8. "github.com/allanpk716/ChineseSubFinder/internal/types"
  9. "github.com/allanpk716/ChineseSubFinder/internal/types/series"
  10. "github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
  11. "github.com/sirupsen/logrus"
  12. "math"
  13. "os"
  14. "path/filepath"
  15. "strings"
  16. )
  17. type Supplier struct {
  18. reqParam types.ReqParam
  19. log *logrus.Logger
  20. topic int
  21. }
  22. func NewSupplier(_reqParam ...types.ReqParam) *Supplier {
  23. sup := Supplier{}
  24. sup.log = log_helper.GetLogger()
  25. sup.topic = common.DownloadSubsPerSite
  26. if len(_reqParam) > 0 {
  27. sup.reqParam = _reqParam[0]
  28. if sup.reqParam.Topic > 0 && sup.reqParam.Topic != sup.topic {
  29. sup.topic = sup.reqParam.Topic
  30. }
  31. }
  32. return &sup
  33. }
  34. func (s Supplier) GetSupplierName() string {
  35. return common.SubSiteShooter
  36. }
  37. func (s Supplier) GetReqParam() types.ReqParam {
  38. return s.reqParam
  39. }
  40. func (s Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
  41. return s.getSubListFromFile(filePath)
  42. }
  43. func (s Supplier) GetSubListFromFile4Series(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  44. return s.downloadSub4Series(seriesInfo)
  45. }
  46. func (s Supplier) GetSubListFromFile4Anime(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  47. return s.downloadSub4Series(seriesInfo)
  48. }
  49. func (s Supplier) getSubListFromFile(filePath string) ([]supplier.SubInfo, error) {
  50. // 可以提供的字幕查询 eng或者chn
  51. const qLan = "Chn"
  52. var outSubInfoList []supplier.SubInfo
  53. var jsonList []SublistShooter
  54. hash, err := s.computeFileHash(filePath)
  55. if err != nil {
  56. return nil, err
  57. }
  58. if hash == "" {
  59. return nil, common.ShooterFileHashIsEmpty
  60. }
  61. fileName := filepath.Base(filePath)
  62. httpClient := pkg.NewHttpClient(s.reqParam)
  63. _, err = httpClient.R().
  64. SetFormData(map[string]string{
  65. "filehash": hash,
  66. "pathinfo": fileName,
  67. "format": "json",
  68. "lang": qLan,
  69. }).
  70. SetResult(&jsonList).
  71. Post(common.SubShooterRootUrl)
  72. if err != nil {
  73. return nil, err
  74. }
  75. for i, shooter := range jsonList {
  76. for _, file := range shooter.Files {
  77. subExt := file.Ext
  78. if strings.Contains(file.Ext, ".") == false {
  79. subExt = "." + subExt
  80. }
  81. data, _, err := pkg.DownFile(file.Link)
  82. if err != nil {
  83. s.log.Error(err)
  84. continue
  85. }
  86. onSub := supplier.NewSubInfo(s.GetSupplierName(), int64(i), fileName, types.ChineseSimple, file.Link, 0, shooter.Delay, subExt, data)
  87. outSubInfoList = append(outSubInfoList, *onSub)
  88. // 如果够了那么多个字幕就返回
  89. if len(outSubInfoList) >= s.topic {
  90. return outSubInfoList, nil
  91. }
  92. // 一层里面,下载一个文件就行了
  93. break
  94. }
  95. }
  96. return outSubInfoList, nil
  97. }
  98. func (s Supplier) getSubListFromKeyword(keyword string) ([]supplier.SubInfo, error) {
  99. panic("not implemented")
  100. }
  101. func (s Supplier) computeFileHash(filePath string) (string, error) {
  102. hash := ""
  103. fp, err := os.Open(filePath)
  104. if err != nil {
  105. return "", err
  106. }
  107. defer fp.Close()
  108. stat, err := fp.Stat()
  109. if err != nil {
  110. return "", err
  111. }
  112. size := float64(stat.Size())
  113. if size < 0xF000 {
  114. return "", common.VideoFileIsTooSmall
  115. }
  116. samplePositions := [4]int64{
  117. 4 * 1024,
  118. int64(math.Floor(size / 3 * 2)),
  119. int64(math.Floor(size / 3)),
  120. int64(size - 8*1024)}
  121. var samples [4][]byte
  122. for i, position := range samplePositions {
  123. samples[i] = make([]byte, 4*1024)
  124. _, err = fp.ReadAt(samples[i], position)
  125. if err != nil {
  126. return "", err
  127. }
  128. }
  129. for _, sample := range samples {
  130. if len(hash) > 0 {
  131. hash += ";"
  132. }
  133. hash += fmt.Sprintf("%x", md5.Sum(sample))
  134. }
  135. return hash, nil
  136. }
  137. func (s Supplier) downloadSub4Series(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  138. var allSupplierSubInfo = make([]supplier.SubInfo, 0)
  139. // 这里拿到的 seriesInfo ,里面包含了,需要下载字幕的 Eps 信息
  140. for _, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
  141. one, err := s.getSubListFromFile(episodeInfo.FileFullPath)
  142. if err != nil {
  143. return nil, err
  144. }
  145. // 需要赋值给字幕结构
  146. for i, _ := range one {
  147. one[i].Season = episodeInfo.Season
  148. one[i].Episode = episodeInfo.Episode
  149. }
  150. allSupplierSubInfo = append(allSupplierSubInfo, one...)
  151. }
  152. // 返回前,需要把每一个 Eps 的 Season Episode 信息填充到每个 SubInfo 中
  153. return allSupplierSubInfo, nil
  154. }
  155. type FilesShooter struct {
  156. Ext string `json:"ext"`
  157. Link string `json:"link"`
  158. }
  159. type SublistShooter struct {
  160. Desc string `json:"desc"`
  161. Delay int64 `json:"delay"`
  162. Files []FilesShooter `json:"files"`
  163. }