video.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package services
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/binary"
  6. "encoding/json"
  7. "errors"
  8. "github.com/PuerkitoBio/goquery"
  9. "github.com/kgiannakakis/mp3duration/src/mp3duration"
  10. "hongze/hongze_ETA_mobile_api/models"
  11. "hongze/hongze_ETA_mobile_api/services/alarm_msg"
  12. "hongze/hongze_ETA_mobile_api/utils"
  13. "html"
  14. "io"
  15. "io/ioutil"
  16. "os"
  17. "strings"
  18. "time"
  19. "unicode"
  20. )
  21. func CreateVideo(report *models.ReportDetail) (err error) {
  22. defer func() {
  23. if err != nil {
  24. utils.FileLog.Error("CreateVideo Err:%s", err.Error())
  25. go alarm_msg.SendAlarmMsg("CreateVideo, Err:"+err.Error(), 3)
  26. //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "Err:"+err.Error(), utils.EmailSendToUsers)
  27. }
  28. }()
  29. ct, err := time.Parse(utils.FormatDateTime, report.CreateTime)
  30. createTime := ct.Format("0102")
  31. videoName := report.Title + "(" + createTime + ")"
  32. content := html.UnescapeString(report.Content)
  33. content = strings.Replace(content, "Powered", "", -1)
  34. content = strings.Replace(content, "by", "", -1)
  35. content = strings.Replace(content, "Froala", "", -1)
  36. content = strings.Replace(content, "Editor", "", -1)
  37. doc, err := goquery.NewDocumentFromReader(strings.NewReader(content))
  38. if err != nil {
  39. return
  40. }
  41. param := new(models.XfSendParam)
  42. param.Common.AppId = utils.XfAPPID
  43. param.Business.Aue = "lame"
  44. param.Business.Sfl = 1
  45. param.Business.Auf = "audio/L16;rate=16000"
  46. param.Business.Vcn = utils.XfVcn
  47. param.Business.Speed = 50
  48. param.Business.Volume = 100
  49. param.Business.Pitch = 50
  50. param.Business.Bgs = 0
  51. param.Business.Tte = "UTF8"
  52. param.Business.Reg = "2"
  53. param.Business.Rdn = "0"
  54. param.Data.Status = 2
  55. videoContent := doc.Text()
  56. saveName := utils.GetRandStringNoSpecialChar(16) + ".mp3"
  57. savePath := "./" + saveName
  58. //if utils.FileIsExist(savePath) {
  59. // os.Remove(savePath)
  60. //}
  61. contentArr := GetChineseCount(videoContent)
  62. for _, v := range contentArr {
  63. newText := v
  64. param.Data.Text = base64.StdEncoding.EncodeToString([]byte(newText))
  65. result, err := json.Marshal(param)
  66. if err != nil {
  67. return err
  68. }
  69. err = GetXfVideo(result, savePath)
  70. if err != nil {
  71. err = errors.New("GetXfVideo Err:" + err.Error())
  72. utils.FileLog.Error("GetXfVideo err", err.Error())
  73. return err
  74. }
  75. time.Sleep(5 * time.Second)
  76. }
  77. uploadUrl, err := UploadAudioAliyun(saveName, savePath)
  78. if err != nil {
  79. err = errors.New("UploadAudioAliyun Err:" + err.Error())
  80. return
  81. }
  82. fileBody, err := ioutil.ReadFile(savePath)
  83. videoSize := len(fileBody)
  84. sizeFloat := (float64(videoSize) / float64(1024)) / float64(1024)
  85. sizeStr := utils.SubFloatToFloatStr(sizeFloat, 2)
  86. playSeconds, err := mp3duration.Calculate(savePath)
  87. if playSeconds <= 0 {
  88. playSeconds, err = utils.GetVideoPlaySeconds(savePath)
  89. if err != nil {
  90. err = errors.New("GetVideoPlaySeconds Err:" + err.Error())
  91. return
  92. }
  93. }
  94. if playSeconds > 0 {
  95. if utils.FileIsExist(savePath) {
  96. os.Remove(savePath)
  97. }
  98. }
  99. err = models.ModifyReportVideo(report.Id, uploadUrl, videoName, sizeStr, playSeconds)
  100. return
  101. }
  102. func GetChineseCount(str1 string) []string {
  103. fontArr := make([]string, 0)
  104. str := ""
  105. count := 0
  106. for _, char := range str1 {
  107. str += string(char)
  108. if unicode.Is(unicode.Han, char) {
  109. count++
  110. if count >= 1700 {
  111. fontArr = append(fontArr, str)
  112. str = ""
  113. count = 0
  114. }
  115. }
  116. }
  117. fontArr = append(fontArr, str)
  118. return fontArr
  119. }
  120. // BoxHeader 信息头
  121. type BoxHeader struct {
  122. Size uint32
  123. FourccType [4]byte
  124. Size64 uint64
  125. }
  126. // GetMP4Duration 获取视频时长,以秒计
  127. func GetMP4Duration(reader io.ReaderAt) (lengthOfTime uint32, err error) {
  128. var info = make([]byte, 0x10)
  129. var boxHeader BoxHeader
  130. var offset int64 = 0
  131. // 获取moov结构偏移
  132. for {
  133. _, err = reader.ReadAt(info, offset)
  134. if err != nil {
  135. return
  136. }
  137. boxHeader = getHeaderBoxInfo(info)
  138. fourccType := getFourccType(boxHeader)
  139. if fourccType == "moov" {
  140. break
  141. }
  142. // 有一部分mp4 mdat尺寸过大需要特殊处理
  143. if fourccType == "mdat" {
  144. if boxHeader.Size == 1 {
  145. offset += int64(boxHeader.Size64)
  146. continue
  147. }
  148. }
  149. offset += int64(boxHeader.Size)
  150. }
  151. // 获取moov结构开头一部分
  152. moovStartBytes := make([]byte, 0x100)
  153. _, err = reader.ReadAt(moovStartBytes, offset)
  154. if err != nil {
  155. return
  156. }
  157. // 定义timeScale与Duration偏移
  158. timeScaleOffset := 0x1C
  159. durationOffest := 0x20
  160. timeScale := binary.BigEndian.Uint32(moovStartBytes[timeScaleOffset : timeScaleOffset+4])
  161. Duration := binary.BigEndian.Uint32(moovStartBytes[durationOffest : durationOffest+4])
  162. lengthOfTime = Duration / timeScale
  163. return
  164. }
  165. // getHeaderBoxInfo 获取头信息
  166. func getHeaderBoxInfo(data []byte) (boxHeader BoxHeader) {
  167. buf := bytes.NewBuffer(data)
  168. binary.Read(buf, binary.BigEndian, &boxHeader)
  169. return
  170. }
  171. // getFourccType 获取信息头类型
  172. func getFourccType(boxHeader BoxHeader) (fourccType string) {
  173. fourccType = string(boxHeader.FourccType[:])
  174. return
  175. }
  176. // CreateReportVideo 生成报告video
  177. func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl, videoName, sizeStr string, playSeconds float64, err error) {
  178. defer func() {
  179. if err != nil {
  180. utils.FileLog.Error("CreateReportVideo Err:%s", err.Error())
  181. go alarm_msg.SendAlarmMsg("CreateReportVideo, reportTitle:"+reportTitle+", Err:"+err.Error(), 3)
  182. //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "CreateReportVideo, reportTitle:" + reportTitle +", Err:"+err.Error(), utils.EmailSendToUsers)
  183. }
  184. }()
  185. if reportContent == "" {
  186. return
  187. }
  188. ct, err := time.Parse(utils.FormatDateTime, reportTime)
  189. if err != nil {
  190. return
  191. }
  192. createTime := ct.Format("0102")
  193. videoName = reportTitle + "(" + createTime + ")"
  194. content := html.UnescapeString(reportContent)
  195. content = strings.Replace(content, "Powered", "", -1)
  196. content = strings.Replace(content, "by", "", -1)
  197. content = strings.Replace(content, "Froala", "", -1)
  198. content = strings.Replace(content, "Editor", "", -1)
  199. doc, err := goquery.NewDocumentFromReader(strings.NewReader(content))
  200. if err != nil {
  201. return
  202. }
  203. param := new(models.XfSendParam)
  204. param.Common.AppId = utils.XfAPPID
  205. param.Business.Aue = "lame"
  206. param.Business.Sfl = 1
  207. param.Business.Auf = "audio/L16;rate=16000"
  208. param.Business.Vcn = utils.XfVcn
  209. param.Business.Speed = 50
  210. param.Business.Volume = 100
  211. param.Business.Pitch = 50
  212. param.Business.Bgs = 0
  213. param.Business.Tte = "UTF8"
  214. param.Business.Reg = "2"
  215. param.Business.Rdn = "0"
  216. param.Data.Status = 2
  217. videoContent := doc.Text()
  218. saveName := utils.GetRandStringNoSpecialChar(16) + ".mp3"
  219. savePath := "./" + saveName
  220. //if utils.FileIsExist(savePath) {
  221. // os.Remove(savePath)
  222. //}
  223. contentArr := GetChineseCount(videoContent)
  224. for _, v := range contentArr {
  225. newText := v
  226. param.Data.Text = base64.StdEncoding.EncodeToString([]byte(newText))
  227. result, tmpErr := json.Marshal(param)
  228. if tmpErr != nil {
  229. return
  230. }
  231. err = GetXfVideo(result, savePath)
  232. if err != nil {
  233. err = errors.New("GetXfVideo Err:" + err.Error())
  234. utils.FileLog.Error("GetXfVideo err", err.Error())
  235. return
  236. }
  237. time.Sleep(5 * time.Second)
  238. }
  239. uploadUrl, err = UploadAudioAliyun(saveName, savePath)
  240. if err != nil {
  241. err = errors.New("UploadAudioAliyun Err:" + err.Error())
  242. return
  243. }
  244. fileBody, err := ioutil.ReadFile(savePath)
  245. videoSize := len(fileBody)
  246. sizeFloat := (float64(videoSize) / float64(1024)) / float64(1024)
  247. sizeStr = utils.SubFloatToFloatStr(sizeFloat, 2)
  248. playSeconds, err = mp3duration.Calculate(savePath)
  249. if playSeconds <= 0 {
  250. playSeconds, err = utils.GetVideoPlaySeconds(savePath)
  251. if err != nil {
  252. err = errors.New("GetVideoPlaySeconds Err:" + err.Error())
  253. return
  254. }
  255. }
  256. if playSeconds > 0 {
  257. if utils.FileIsExist(savePath) {
  258. os.Remove(savePath)
  259. }
  260. }
  261. return
  262. }