shooter.go 4.5 KB

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