xunlei.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package xunlei
  2. import (
  3. "crypto/sha1"
  4. "fmt"
  5. "github.com/allanpk716/ChineseSubFinder/internal/common"
  6. "github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
  7. "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  8. "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
  9. "github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
  10. "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
  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. defer func() {
  53. s.log.Debugln(s.GetSupplierName(), filePath, "End...")
  54. }()
  55. s.log.Debugln(s.GetSupplierName(), filePath, "Start...")
  56. cid, err := s.getCid(filePath)
  57. var jsonList SublistSliceXunLei
  58. var tmpXunLeiSubListChinese = make([]SublistXunLei, 0)
  59. var outSubList []supplier.SubInfo
  60. if len(cid) == 0 {
  61. return nil, common.XunLeiCIdIsEmpty
  62. }
  63. httpClient := my_util.NewHttpClient(s.reqParam)
  64. resp, err := httpClient.R().
  65. SetResult(&jsonList).
  66. Get(fmt.Sprintf(common.SubXunLeiRootUrl, cid))
  67. if err != nil {
  68. if resp != nil {
  69. s.log.Errorln(s.GetSupplierName(), "NewHttpClient:", filePath, err.Error())
  70. notify_center.Notify.Add(s.GetSupplierName()+" NewHttpClient", fmt.Sprintf("filePath: %s, resp: %s, error: %s", filePath, resp.String(), err.Error()))
  71. }
  72. return nil, err
  73. }
  74. // 剔除空的
  75. for _, v := range jsonList.Sublist {
  76. if len(v.Scid) > 0 && v.Scid != "" {
  77. // 符合中文语言的先加入列表
  78. tmpLang := language.LangConverter4Sub_Supplier(v.Language)
  79. if language.HasChineseLang(tmpLang) == true && sub_parser_hub.IsSubTypeWanted(v.Sname) == true {
  80. tmpXunLeiSubListChinese = append(tmpXunLeiSubListChinese, v)
  81. }
  82. }
  83. }
  84. // TODO 这里需要考虑,可以设置为高级选项,不够就用 unknow 来补充
  85. // 如果不够,再补 unknow
  86. if len(tmpXunLeiSubListChinese) < s.topic {
  87. for _, v := range jsonList.Sublist {
  88. if len(tmpXunLeiSubListChinese) >= s.topic {
  89. break
  90. }
  91. if len(v.Scid) > 0 && v.Scid != "" {
  92. tmpLang := language.LangConverter4Sub_Supplier(v.Language)
  93. if language.HasChineseLang(tmpLang) == false {
  94. tmpXunLeiSubListChinese = append(tmpXunLeiSubListChinese, v)
  95. }
  96. }
  97. }
  98. }
  99. // 再开始下载字幕
  100. for i, v := range tmpXunLeiSubListChinese {
  101. tmpLang := language.LangConverter4Sub_Supplier(v.Language)
  102. data, filename, err := my_util.DownFile(v.Surl)
  103. if err != nil {
  104. s.log.Errorln("xunlei pkg.DownFile:", err)
  105. continue
  106. }
  107. ext := ""
  108. if filename == "" {
  109. ext = filepath.Ext(v.Surl)
  110. } else {
  111. ext = filepath.Ext(filename)
  112. }
  113. outSubList = append(outSubList, *supplier.NewSubInfo(s.GetSupplierName(), int64(i), v.Sname, tmpLang, v.Surl, v.Svote, v.Roffset, ext, data))
  114. }
  115. return outSubList, nil
  116. }
  117. func (s Supplier) getSubListFromKeyword(keyword string) ([]supplier.SubInfo, error) {
  118. panic("not implemented")
  119. }
  120. //getCid 获取指定文件的唯一 cid
  121. func (s Supplier) getCid(filePath string) (string, error) {
  122. hash := ""
  123. sha1Ctx := sha1.New()
  124. fp, err := os.Open(filePath)
  125. if err != nil {
  126. return "", err
  127. }
  128. defer fp.Close()
  129. stat, err := fp.Stat()
  130. if err != nil {
  131. return "", err
  132. }
  133. fileLength := stat.Size()
  134. if fileLength < 0xF000 {
  135. return "", err
  136. }
  137. bufferSize := int64(0x5000)
  138. positions := []int64{0, int64(math.Floor(float64(fileLength) / 3)), fileLength - bufferSize}
  139. for _, position := range positions {
  140. var buffer = make([]byte, bufferSize)
  141. _, err = fp.Seek(position, 0)
  142. if err != nil {
  143. return "", err
  144. }
  145. _, err = fp.Read(buffer)
  146. if err != nil {
  147. return "", err
  148. }
  149. sha1Ctx.Write(buffer)
  150. }
  151. hash = fmt.Sprintf("%X", sha1Ctx.Sum(nil))
  152. return hash, nil
  153. }
  154. func (s Supplier) downloadSub4Series(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
  155. var allSupplierSubInfo = make([]supplier.SubInfo, 0)
  156. // 这里拿到的 seriesInfo ,里面包含了,需要下载字幕的 Eps 信息
  157. for _, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
  158. one, err := s.getSubListFromFile(episodeInfo.FileFullPath)
  159. if err != nil {
  160. s.log.Errorln(s.GetSupplierName(), "getSubListFromFile", episodeInfo.Season, episodeInfo.Episode,
  161. episodeInfo.FileFullPath)
  162. continue
  163. }
  164. if one == nil {
  165. // 没有搜索到字幕
  166. s.log.Infoln(s.GetSupplierName(), "Not Find Sub can be download",
  167. episodeInfo.Title, episodeInfo.Season, episodeInfo.Episode)
  168. continue
  169. }
  170. // 需要赋值给字幕结构
  171. for i, _ := range one {
  172. one[i].Season = episodeInfo.Season
  173. one[i].Episode = episodeInfo.Episode
  174. }
  175. allSupplierSubInfo = append(allSupplierSubInfo, one...)
  176. }
  177. // 返回前,需要把每一个 Eps 的 Season Episode 信息填充到每个 SubInfo 中
  178. return allSupplierSubInfo, nil
  179. }
  180. type SublistXunLei struct {
  181. Scid string `json:"scid"`
  182. Sname string `json:"sname"`
  183. Language string `json:"language"`
  184. Rate string `json:"rate"`
  185. Surl string `json:"surl"`
  186. Svote int64 `json:"svote"`
  187. Roffset int64 `json:"roffset"`
  188. }
  189. type SublistSliceXunLei struct {
  190. Sublist []SublistXunLei
  191. }
  192. const LangUnknow = "未知语言"