video.go 10 KB

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