xunlei.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package xunlei
  2. import (
  3. "crypto/sha1"
  4. "fmt"
  5. "github.com/allanpk716/ChineseSubFinder/internal/common"
  6. "github.com/allanpk716/ChineseSubFinder/internal/pkg"
  7. "github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
  8. "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  9. "github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
  10. "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
  11. "github.com/allanpk716/ChineseSubFinder/internal/types"
  12. "github.com/allanpk716/ChineseSubFinder/internal/types/series"
  13. "github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
  14. "github.com/sirupsen/logrus"
  15. "math"
  16. "os"
  17. "path/filepath"
  18. )
  19. type Supplier struct {
  20. reqParam types.ReqParam
  21. log *logrus.Logger
  22. topic int
  23. }
  24. func NewSupplier(_reqParam ...types.ReqParam) *Supplier {
  25. sup := Supplier{}
  26. sup.log = log_helper.GetLogger()
  27. sup.topic = common.DownloadSubsPerSite
  28. if len(_reqParam) > 0 {
  29. sup.reqParam = _reqParam[0]
  30. if sup.reqParam.Topic > 0 && sup.reqParam.Topic != sup.topic {
  31. sup.topic = sup.reqParam.Topic
  32. }
  33. }
  34. return &sup
  35. }
  36. func (s Supplier) GetSupplierName() string {
  37. return common.SubSiteXunLei
  38. }
  39. func (s Supplier) GetReqParam() types.ReqParam {
  40. return s.reqParam
  41. }
  42. func (s Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
  43. return s.getSubListFromFile(filePath)
  44. }
  45. func (s Supplier) GetSubListFromFile4Series(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  46. return s.downloadSub4Series(seriesInfo)
  47. }
  48. func (s Supplier) GetSubListFromFile4Anime(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  49. return s.downloadSub4Series(seriesInfo)
  50. }
  51. func (s Supplier) getSubListFromFile(filePath string) ([]supplier.SubInfo, error) {
  52. cid, err := s.getCid(filePath)
  53. var jsonList SublistSliceXunLei
  54. var tmpXunLeiSubListChinese = make([]SublistXunLei, 0)
  55. var outSubList []supplier.SubInfo
  56. if len(cid) == 0 {
  57. return outSubList, common.XunLeiCIdIsEmpty
  58. }
  59. httpClient := pkg.NewHttpClient(s.reqParam)
  60. resp, err := httpClient.R().
  61. SetResult(&jsonList).
  62. Get(fmt.Sprintf(common.SubXunLeiRootUrl, cid))
  63. if err != nil {
  64. if resp != nil {
  65. s.log.Errorln("xunlei NewHttpClient:", resp.String())
  66. notify_center.Notify.Add("xunlei NewHttpClient", fmt.Sprintf("resp: %s, error: %s", resp.String(), err.Error()))
  67. }
  68. return outSubList, err
  69. }
  70. // 剔除空的
  71. for _, v := range jsonList.Sublist {
  72. if len(v.Scid) > 0 && v.Scid != "" {
  73. // 符合中文语言的先加入列表
  74. tmpLang := language.LangConverter(v.Language)
  75. if language.HasChineseLang(tmpLang) == true && sub_helper.IsSubTypeWanted(v.Sname) == true {
  76. tmpXunLeiSubListChinese = append(tmpXunLeiSubListChinese, v)
  77. }
  78. }
  79. }
  80. // TODO 这里需要考虑,可以设置为高级选项,不够就用 unknow 来补充
  81. // 如果不够,再补 unknow
  82. if len(tmpXunLeiSubListChinese) < s.topic {
  83. for _, v := range jsonList.Sublist {
  84. if len(tmpXunLeiSubListChinese) >= s.topic {
  85. break
  86. }
  87. if len(v.Scid) > 0 && v.Scid != "" {
  88. tmpLang := language.LangConverter(v.Language)
  89. if language.HasChineseLang(tmpLang) == false {
  90. tmpXunLeiSubListChinese = append(tmpXunLeiSubListChinese, v)
  91. }
  92. }
  93. }
  94. }
  95. // 再开始下载字幕
  96. for i, v := range tmpXunLeiSubListChinese {
  97. tmpLang := language.LangConverter(v.Language)
  98. data, filename, err := pkg.DownFile(v.Surl)
  99. if err != nil {
  100. s.log.Errorln("xunlei pkg.DownFile:", err)
  101. continue
  102. }
  103. ext := ""
  104. if filename == "" {
  105. ext = filepath.Ext(v.Surl)
  106. } else {
  107. ext = filepath.Ext(filename)
  108. }
  109. outSubList = append(outSubList, *supplier.NewSubInfo(s.GetSupplierName(), int64(i), v.Sname, tmpLang, v.Surl, v.Svote, v.Roffset, ext, data))
  110. }
  111. return outSubList, nil
  112. }
  113. func (s Supplier) getSubListFromKeyword(keyword string) ([]supplier.SubInfo, error) {
  114. panic("not implemented")
  115. }
  116. //getCid 获取指定文件的唯一 cid
  117. func (s Supplier) getCid(filePath string) (string, error) {
  118. hash := ""
  119. sha1Ctx := sha1.New()
  120. fp, err := os.Open(filePath)
  121. if err != nil {
  122. return "", err
  123. }
  124. defer fp.Close()
  125. stat, err := fp.Stat()
  126. if err != nil {
  127. return "", err
  128. }
  129. fileLength := stat.Size()
  130. if fileLength < 0xF000 {
  131. return "", err
  132. }
  133. bufferSize := int64(0x5000)
  134. positions := []int64{0, int64(math.Floor(float64(fileLength) / 3)), fileLength - bufferSize}
  135. for _, position := range positions {
  136. var buffer = make([]byte, bufferSize)
  137. _, err = fp.Seek(position, 0)
  138. if err != nil {
  139. return "", err
  140. }
  141. _, err = fp.Read(buffer)
  142. if err != nil {
  143. return "", err
  144. }
  145. sha1Ctx.Write(buffer)
  146. }
  147. hash = fmt.Sprintf("%X", sha1Ctx.Sum(nil))
  148. return hash, nil
  149. }
  150. func (s Supplier) downloadSub4Series(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  151. var allSupplierSubInfo = make([]supplier.SubInfo, 0)
  152. // 这里拿到的 seriesInfo ,里面包含了,需要下载字幕的 Eps 信息
  153. for _, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
  154. one, err := s.getSubListFromFile(episodeInfo.FileFullPath)
  155. if err != nil {
  156. return nil, err
  157. }
  158. // 需要赋值给字幕结构
  159. for i, _ := range one {
  160. one[i].Season = episodeInfo.Season
  161. one[i].Episode = episodeInfo.Episode
  162. }
  163. allSupplierSubInfo = append(allSupplierSubInfo, one...)
  164. }
  165. // 返回前,需要把每一个 Eps 的 Season Episode 信息填充到每个 SubInfo 中
  166. return allSupplierSubInfo, nil
  167. }
  168. type SublistXunLei struct {
  169. Scid string `json:"scid"`
  170. Sname string `json:"sname"`
  171. Language string `json:"language"`
  172. Rate string `json:"rate"`
  173. Surl string `json:"surl"`
  174. Svote int64 `json:"svote"`
  175. Roffset int64 `json:"roffset"`
  176. }
  177. type SublistSliceXunLei struct {
  178. Sublist []SublistXunLei
  179. }
  180. const LangUnknow = "未知语言"