shooter.go 4.7 KB

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