雪场华为云VOD视频上传服务程序
lyg
2025-01-24 b9a246da2db1e8a7c37a9d02df29e0dbc82c9579
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package com.ld.vps.service;
 
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.ld.vps.bean.BitsPressToken;
import com.ld.vps.bean.UploadTaskInfo;
import com.ld.vps.config.TrailInfo;
import com.ld.vps.dao.BitsPressTokenRepository;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import java.io.File;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
 
@Component
public class BitsPressService {
  Logger logger = LoggerFactory.getLogger(BitsPressService.class);
 
  String baseUrl = "http://1.92.143.71";
  String refreshTkUrl = baseUrl + "/identity/admin/RefreshToken";
  String getTopQueueItemUrl = baseUrl + "/ugc/api/GetTopQueueItem";
  String getNewGuidUrl = baseUrl + "/app/admin/GetNewGuid";
  String createProductUrl = baseUrl + "/store/admin/NewStoreProductWithList";
  String initFileUrl = baseUrl + "/file/admin/InitFile";
  String uploadFileUrl = baseUrl + "/file/admin/Upload";
  String cwd = System.getProperty("user.dir");
 
  @Autowired
  BitsPressTokenRepository tokenRepo;
  @Autowired
  TrailInfo trailInfo;
  BitsPressToken token;
 
  BitsPressService() {
  }
 
  @PostConstruct
  private void init() {
    List<BitsPressToken> tks = tokenRepo.findAll();
    if (tks.isEmpty()) {
      this.token = new BitsPressToken();
      String tk = FileUtil.readString(cwd + "/token", Charset.defaultCharset());
      this.token.setToken(tk);
      tokenRepo.save(this.token);
    } else {
      this.token = tks.get(0);
    }
 
//    this.refreshToken();
  }
 
  void saveToken() {
    tokenRepo.save(this.token);
    FileUtil.writeString(this.token.getToken(), cwd + "/token", Charset.defaultCharset());
  }
 
  public String post(String url, Map<String, Object> params) {
    return this.post(url, JSONUtil.toJsonStr(params));
  }
 
  public String post(String url, String params) {
    HttpRequest req = HttpUtil.createPost(url);
    req.auth(this.getToken())
        .addHeaders(MapUtil.builder("Content-Type", "application/json")
            .put("accept", "text/plain").build())
        .body(params);
    try {
      HttpResponse resp = req.execute();
      if (resp.getStatus() != 200) {
        throw new RuntimeException("请求失败!");
      }
      return resp.body();
    } catch (Exception e) {
      this.refreshToken(null);
      req.auth(this.getToken());
      req.body(JSONUtil.toJsonStr(params));
      return req.execute().body();
    }
  }
 
  public void refreshToken(String token) {
    HttpRequest req = HttpUtil.createPost(refreshTkUrl);
    req.addHeaders(MapUtil.builder("Content-Type", "application/json")
        .put("accept", "text/plain").build());
    req.body(JSONUtil.toJsonStr(MapUtil.of("token", (token != null ? token : this.token.getToken()).substring(7))));
    String resp = req.execute().body();
    this.token.setToken("bearer " + JSONUtil.parseObj(resp).getJSONObject("data").getStr("token"));
    this.saveToken();
  }
 
  public String getToken() {
    return token.getToken();
  }
 
  public String getTopQueueItem(Integer count) {
    return this.post(getTopQueueItemUrl, MapUtil.builder("refCode", (Object) trailInfo.getId()).put("count", count).build());
  }
 
  public String getNewGuid() {
    String resp = this.post(getNewGuidUrl, "");
    return JSONUtil.parseObj(resp).getStr("data");
  }
 
  public Long createProduct(UploadTaskInfo task) {
    String prodName = DateUtil.formatDateTime(new Date());
    String beginDate = DateUtil.formatDate(new Date());
    String shotDate = beginDate;
 
    String body = "{\"appId\":\"1\",\"storeId\":1,\"newProductRequests\":[{\"type\":\"product\",\"sysType\":\"Cms\",\"state\":\"Normal\",\"allowDonate\":false,\"linkPathList\":[\"1\\\\2\"],\"name\":\"商品名称\",\"icon\":\"商品封面\",\"typeId\":4,\"beginDate\":\"开始日期\",\"endDate\":\"2099-12-31\",\"dataRequests\":[{\"baseType\":\"String\",\"groupId\":4,\"order\":0,\"sequenceNum\":\"67687FA0\",\"strValue\":\"用户GUID\",\"typeFieldId\":5},{\"baseType\":\"String\",\"groupId\":4,\"order\":1,\"sequenceNum\":\"3DDAABF3\",\"strValue\":\"视频ID\",\"typeFieldId\":6},{\"baseType\":\"String\",\"groupId\":4,\"order\":2,\"sequenceNum\":\"833ACCDF\",\"strValue\":\"雪道ID\",\"typeFieldId\":7,\"newDataAndFileLinkListRequest\":null,\"addLinkItems\":[]},{\"baseType\":\"DateTime\",\"groupId\":4,\"order\":3,\"sequenceNum\":\"1C16BF75\",\"dateValue\":\"拍摄时间\",\"typeFieldId\":9}],\"newDefaultSaleMethodRequests\":[{\"name\":\"默认销售方式\",\"type\":\"defaultSaleMethod\",\"state\":\"Normal\",\"saleType\":\"Normal\",\"timeType\":\"Permanent\",\"allowEvent\":true,\"price\":商品价格,\"beginDate\":\"开始日期\",\"endDate\":\"2099-12-31\"}],\"newCmsItemLinkListRequest\":[],\"newQRCodeWithProductRequests\":[]}]}"
        .replaceAll("商品名称", prodName)
        .replaceAll("商品封面", task.getCover())
        .replaceAll("开始日期", beginDate)
        .replaceAll("用户GUID", task.getUserId())
        .replaceAll("视频ID", task.getAssetId())
        .replaceAll("雪道ID", trailInfo.getId())
        .replaceAll("拍摄时间", shotDate)
        .replaceAll("商品价格", trailInfo.getPrice());
    String resp = this.post(createProductUrl, body);
    Long prodId = JSONUtil.parseObj(resp).getJSONArray("data").getLong(0);
    task.setBitsPressProdId(prodId);
    task.setBitsPressProdInfo(body);
    return prodId;
  }
 
  public String initFile(String file, String md5, long fileSize) {
    String body = "{\"name\":\"视频封面\",\"md5\":\"视频文件MD5\",\"fileName\":\"视频封面\",\"extension\":\"jpg\",\"fileType\":\"Picture\",\"metaData\":\"{\\\"name\\\":\\\"文件夹类型\\\",\\\"size\\\":文件大小,\\\"ext\\\":\\\"jpg\\\",\\\"fileName\\\":\\\"视频封面.jpg\\\"}\",\"type\":\"Image\",\"icon\":\"\",\"size\":文件大小,\"accessType\":\"Public\",\"appId\":\"1\"}"
        .replaceAll("视频文件MD5", md5)
        .replaceAll("文件大小", fileSize + "");
    this.post(initFileUrl, body);
    return this.post(initFileUrl, body);
  }
 
  public String uploadFile(String file, String md5) {
    HttpRequest req = HttpUtil.createPost(uploadFileUrl);
    req.auth(this.getToken())
        .addHeaders(MapUtil.builder("Content-Type", "application/json")
            .put("accept", "text/plain").build());
    req.form("Md5", md5);
    req.form("Offset", 0);
    req.form("IsLastOne", true);
    req.form("AppId", "1");
    req.form("file", FileUtil.file(file));
    HttpResponse resp = req.execute();
    if (resp.getStatus() != 200) {
      throw new RuntimeException("上传文件失败!");
    }
    return resp.body();
  }
 
  public void uploadCover(UploadTaskInfo task) {
    String coverFile = this.generateCover(task.getFilePath());
    File file = new File(coverFile);
    long fileSize = file.length();
    String md5 = DigestUtil.md5Hex(file);
    task.setCover(md5);
    initFile(coverFile, md5, fileSize);
    uploadFile(coverFile, md5);
  }
 
  /**
   * 获取指定的视频文件后进行封面截图为jpg并保存到指定目录
   *
   * @param videoFile 视频媒体文件
   */
  public String generateCover(String videoFile) {
    String coverFile = FileUtil.getTmpDir() + "\\cover.jpg";
    if (FileUtil.exist(coverFile)) {
      FileUtil.del(coverFile);
    }
 
    try {
      Process proc = RuntimeUtil.exec(cwd + "/ffmpeg.exe", "-loglevel", "quiet", "-i", videoFile, "-ss", "00:00:02", "-vframes", "1", coverFile);
      proc.waitFor(10, TimeUnit.SECONDS);
      if (proc.isAlive()) {
        proc.destroy();
      }
      logger.debug("ffmpeg提取视频第一帧完成");
    } catch (Exception e) {
      logger.error(e.getMessage());
      throw new RuntimeException("截取封面失败!");
    }
    return coverFile;
  }
}