• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "MediaLibraryCloneRestoreCVAnalysis"
17 
18 #include "clone_restore_cv_analysis.h"
19 
20 #include "backup_database_utils.h"
21 #include "backup_file_utils.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "upgrade_restore_task_report.h"
25 
26 namespace OHOS::Media {
27 const int32_t PAGE_SIZE = 200;
28 const std::vector<std::string> EFFECTLINE_ID = { "fileId", "prefileId" };
29 const std::vector<std::string> EFFECTLINE_URI = { "fileUri", "prefileUri" };
30 const std::string EFFECTLINE_TYPE_HITCHCOCK = "TYPE_HITCHCOCK";
31 const std::string EFFECTLINE_TYPE_UAV = "TYPE_UAV";
32 const std::string EFFECTLINE_TYPE_HILIGHT_SLOW = "TYPE_HILIGHT_SLOW";
33 const std::string EFFECTLINE_TYPE_HILIGHT_CLIP = "TYPE_HILIGHT_CLIP";
34 const std::string EFFECTLINE_TYPE_MASK1 = "TYPE_MASK1";
35 const std::string EFFECTLINE_TYPE_MASK2 = "TYPE_MASK2";
36 const std::string HIGHLIGHT_ASSET_URI_PREFIX = "file://media/highlight/video/";
37 const std::string HIGHLIGHT_ASSET_URI_SUFFIX = "?oper=highlight";
38 const std::string PHOTO_URI_PREFIX = "file://media/Photo/";
39 const std::string GARBLE_DST_PATH = "/storage/media/local/files";
40 const std::string RESTORE_STATUS_SUCCESS = "1";
41 
42 template<typename Key, typename Value>
GetValueFromMap(const std::unordered_map<Key,Value> & map,const Key & key,const Value & defaultValue=Value ())43 Value GetValueFromMap(const std::unordered_map<Key, Value> &map, const Key &key, const Value &defaultValue = Value())
44 {
45     auto it = map.find(key);
46     CHECK_AND_RETURN_RET(it != map.end(), defaultValue);
47     return it->second;
48 }
49 
Init(int32_t sceneCode,const std::string & taskId,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::shared_ptr<NativeRdb::RdbStore> mediaRdb,const std::string & backupRestoreDir)50 void CloneRestoreCVAnalysis::Init(int32_t sceneCode, const std::string &taskId,
51     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
52     std::shared_ptr<NativeRdb::RdbStore> mediaRdb, const std::string &backupRestoreDir)
53 {
54     sceneCode_ = sceneCode;
55     taskId_ = taskId;
56     mediaLibraryRdb_ = mediaLibraryRdb;
57     mediaRdb_ = mediaRdb;
58 
59     assetPath_ = backupRestoreDir + "/storage/media/local/files/highlight/video/";
60     isHighlightVideoDirExist_ = MediaFileUtils::IsDirectory(assetPath_);
61     MEDIA_INFO_LOG("/highlight/video/ source dir %{public}s.", isHighlightVideoDirExist_ ? "exist" : "don't exist");
62     garblePath_ = backupRestoreDir + GARBLE_DST_PATH;
63 }
64 
RestoreAlbums(CloneRestoreHighlight & cloneHighlight)65 void CloneRestoreCVAnalysis::RestoreAlbums(CloneRestoreHighlight &cloneHighlight)
66 {
67     CHECK_AND_RETURN_LOG(mediaRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr.");
68     CHECK_AND_RETURN_LOG(cloneHighlight.IsCloneHighlight(), "clone highlight flag is false.");
69 
70     MEDIA_INFO_LOG("restore highlight cv analysis album start.");
71     int64_t startRestoreAssetSdTime = MediaFileUtils::UTCTimeMilliSeconds();
72     RestoreAssetSdMap(cloneHighlight);
73     int64_t startRestoreAlbumAssetTime = MediaFileUtils::UTCTimeMilliSeconds();
74     RestoreAlbumAssetMap(cloneHighlight);
75     int64_t startUpdatePlayInfoTime = MediaFileUtils::UTCTimeMilliSeconds();
76     std::vector<int32_t> updateHighlightIds;
77     UpdateHighlightPlayInfos(cloneHighlight, updateHighlightIds);
78     cloneHighlight.UpdateHighlightStatus(updateHighlightIds);
79     int64_t endTime = MediaFileUtils::UTCTimeMilliSeconds();
80     MEDIA_INFO_LOG("TimeCost: RestoreAlbums: %{public}" PRId64 ", RestoreAssetSdMap: %{public}" PRId64
81         ", RestoreAlbumAssetMap: %{public}" PRId64 ", UpdateHighlightPlayInfos: %{public}" PRId64,
82         endTime - startRestoreAssetSdTime, startRestoreAlbumAssetTime - startRestoreAssetSdTime,
83         startUpdatePlayInfoTime - startRestoreAlbumAssetTime, endTime - startUpdatePlayInfoTime);
84     restoreTimeCost_ += endTime - startRestoreAssetSdTime;
85     cloneHighlight.UpdateRestoreTimeCost(restoreTimeCost_);
86     ReportCloneRestoreCVAnalysisTask();
87 }
88 
RestoreAssetSdMap(CloneRestoreHighlight & cloneHighlight)89 void CloneRestoreCVAnalysis::RestoreAssetSdMap(CloneRestoreHighlight &cloneHighlight)
90 {
91     const std::string QUERY_SQL = "SELECT * FROM tab_analysis_asset_sd_map LIMIT ?, ?";
92     int32_t rowCount = 0;
93     int32_t offset = 0;
94     do {
95         std::vector<NativeRdb::ValuesBucket> values;
96         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
97         auto resultSet = BackupDatabaseUtils::QuerySql(mediaRdb_, QUERY_SQL, params);
98         CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
99         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
100             int32_t oldFileId = GetInt32Val("map_asset_source", resultSet);
101             int32_t oldAssetId = GetInt32Val("map_asset_destination", resultSet);
102             NativeRdb::ValuesBucket value;
103             value.PutInt("map_asset_source", cloneHighlight.GetNewHighlightPhotoId(oldFileId));
104             value.PutInt("map_asset_destination", cloneHighlight.GetNewHighlightPhotoId(oldAssetId));
105             values.emplace_back(value);
106         }
107         resultSet->GetRowCount(rowCount);
108         offset += PAGE_SIZE;
109         resultSet->Close();
110         InsertIntoAssetSdMap(values);
111     } while (rowCount == PAGE_SIZE);
112 }
113 
RestoreAlbumAssetMap(CloneRestoreHighlight & cloneHighlight)114 void CloneRestoreCVAnalysis::RestoreAlbumAssetMap(CloneRestoreHighlight &cloneHighlight)
115 {
116     const std::string QUERY_SQL = "SELECT tab_analysis_album_asset_map.* FROM tab_analysis_album_asset_map "
117         " INNER JOIN tab_highlight_album AS h ON tab_analysis_album_asset_map.map_album = h.id "
118         " WHERE h.highlight_status > 0 LIMIT ?, ?";
119     int32_t rowCount = 0;
120     int32_t offset = 0;
121     do {
122         std::vector<NativeRdb::ValuesBucket> values;
123         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
124         auto resultSet = BackupDatabaseUtils::QuerySql(mediaRdb_, QUERY_SQL, params);
125         CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
126         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
127             int32_t oldAlbumId = GetInt32Val("map_album", resultSet);
128             int32_t oldAssetId = GetInt32Val("map_asset", resultSet);
129             NativeRdb::ValuesBucket value;
130             value.PutInt("map_album", cloneHighlight.GetNewHighlightAlbumId(oldAlbumId));
131             value.PutInt("map_asset", cloneHighlight.GetNewHighlightPhotoId(oldAssetId));
132             values.emplace_back(value);
133         }
134         resultSet->GetRowCount(rowCount);
135         offset += PAGE_SIZE;
136         resultSet->Close();
137         InsertIntoAlbumAssetMap(values);
138     } while (rowCount == PAGE_SIZE);
139 }
140 
InsertIntoAssetSdMap(std::vector<NativeRdb::ValuesBucket> & values)141 void CloneRestoreCVAnalysis::InsertIntoAssetSdMap(std::vector<NativeRdb::ValuesBucket> &values)
142 {
143     int64_t rowNum = 0;
144     int32_t errCode = BatchInsertWithRetry("tab_analysis_asset_sd_map", values, rowNum);
145     assetSdSuccessCnt_ += rowNum;
146     CHECK_AND_RETURN(errCode != E_OK || rowNum != static_cast<int64_t>(values.size()));
147     int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
148     ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
149         "insert into sdMap fail, num:" + std::to_string(failNums));
150     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
151     assetSdFailedCnt_ += failNums;
152 }
153 
InsertIntoAlbumAssetMap(std::vector<NativeRdb::ValuesBucket> & values)154 void CloneRestoreCVAnalysis::InsertIntoAlbumAssetMap(std::vector<NativeRdb::ValuesBucket> &values)
155 {
156     int64_t rowNum = 0;
157     int32_t errCode = BatchInsertWithRetry("tab_analysis_album_asset_map", values, rowNum);
158     albumAssetSuccessCnt_ += rowNum;
159     CHECK_AND_RETURN(errCode != E_OK || rowNum != static_cast<int64_t>(values.size()));
160     int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
161     ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
162         "insert into AssetMap fail, num:" + std::to_string(failNums));
163     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
164     albumAssetFailedCnt_ += failNums;
165 }
166 
BatchInsertWithRetry(const std::string & tableName,const std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)167 int32_t CloneRestoreCVAnalysis::BatchInsertWithRetry(const std::string &tableName,
168     const std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
169 {
170     CHECK_AND_RETURN_RET(!values.empty(), 0);
171     int32_t errCode = E_ERR;
172     TransactionOperations trans{ __func__ };
173     trans.SetBackupRdbStore(mediaLibraryRdb_);
174     std::function<int(void)> func = [&]()->int {
175         errCode = trans.BatchInsert(rowNum, tableName, values);
176         CHECK_AND_PRINT_LOG(errCode == E_OK,
177             "InsertSql failed, errCode: %{public}d, rowNum: %{public}" PRId64, errCode, rowNum);
178         return errCode;
179     };
180     errCode = trans.RetryTrans(func, true);
181     CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
182     return errCode;
183 }
184 
ParsePlayInfo(const std::string & oldPlayInfo,CloneRestoreHighlight & cloneHighlight)185 std::string CloneRestoreCVAnalysis::ParsePlayInfo(const std::string &oldPlayInfo, CloneRestoreHighlight &cloneHighlight)
186 {
187     nlohmann::json newPlayInfo = nlohmann::json::parse(oldPlayInfo, nullptr, false);
188     CHECK_AND_RETURN_RET_LOG(!newPlayInfo.is_discarded(), cloneHighlight.GetDefaultPlayInfo(),
189         "parse json string failed.");
190     if (newPlayInfo["effectline"].contains("effectline")) {
191         for (size_t effectlineIndex = 0; effectlineIndex < newPlayInfo["effectline"]["effectline"].size();
192             effectlineIndex++) {
193             ParseEffectline(newPlayInfo, effectlineIndex, cloneHighlight);
194         }
195     }
196     if (newPlayInfo.contains("timeline")) {
197         for (size_t timelineIndex = 0; timelineIndex < newPlayInfo["timeline"].size(); timelineIndex++) {
198             ParseTimeline(newPlayInfo, timelineIndex, cloneHighlight);
199         }
200     }
201     return newPlayInfo.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
202 }
203 
ParseEffectline(nlohmann::json & newPlayInfo,size_t effectlineIndex,CloneRestoreHighlight & cloneHighlight)204 void CloneRestoreCVAnalysis::ParseEffectline(nlohmann::json &newPlayInfo, size_t effectlineIndex,
205     CloneRestoreHighlight &cloneHighlight)
206 {
207     if (newPlayInfo["effectline"]["effectline"][effectlineIndex].contains("effectVideoUri")) {
208         std::string oldEffectVideoUri = newPlayInfo["effectline"]["effectline"][effectlineIndex]["effectVideoUri"];
209         if (MediaFileUtils::StartsWith(oldEffectVideoUri, PHOTO_URI_PREFIX)) {
210             newPlayInfo["effectline"]["effectline"][effectlineIndex]["effectVideoUri"] =
211                 GetNewPhotoUriByUri(oldEffectVideoUri, cloneHighlight);
212         } else if (MediaFileUtils::StartsWith(oldEffectVideoUri, HIGHLIGHT_ASSET_URI_PREFIX)) {
213             newPlayInfo["effectline"]["effectline"][effectlineIndex]["effectVideoUri"] =
214                 GetNewEffectVideoUri(oldEffectVideoUri, cloneHighlight);
215         }
216     }
217 
218     bool cond = newPlayInfo["effectline"]["effectline"][effectlineIndex].contains("effect") &&
219         newPlayInfo["effectline"]["effectline"][effectlineIndex]["effect"] == EFFECTLINE_TYPE_MASK2 &&
220         newPlayInfo["effectline"]["effectline"][effectlineIndex].contains("transitionVideoUri");
221     if (cond) {
222         std::string transVideoUri = GetNewTransitionVideoUri(
223             newPlayInfo["effectline"]["effectline"][effectlineIndex]["transitionVideoUri"], cloneHighlight);
224         newPlayInfo["effectline"]["effectline"][effectlineIndex]["transitionVideoUri"] = transVideoUri;
225 
226         cond = (effectlineIndex > 0 &&
227             newPlayInfo["effectline"]["effectline"][effectlineIndex - 1].contains("effect") &&
228             newPlayInfo["effectline"]["effectline"][effectlineIndex - 1]["effect"] == EFFECTLINE_TYPE_MASK1 &&
229             newPlayInfo["effectline"]["effectline"][effectlineIndex - 1].contains("transitionVideoUri"));
230         CHECK_AND_EXECUTE(!cond,
231             newPlayInfo["effectline"]["effectline"][effectlineIndex - 1]["transitionVideoUri"] = transVideoUri);
232     }
233 
234     ParseEffectlineFileData(newPlayInfo, effectlineIndex, cloneHighlight);
235 }
236 
ParseEffectlineFileData(nlohmann::json & newPlayInfo,size_t effectlineIndex,CloneRestoreHighlight & cloneHighlight)237 void CloneRestoreCVAnalysis::ParseEffectlineFileData(nlohmann::json &newPlayInfo, size_t effectlineIndex,
238     CloneRestoreHighlight &cloneHighlight)
239 {
240     for (size_t infoIndex = 0; infoIndex < EFFECTLINE_ID.size(); infoIndex++) {
241         if (newPlayInfo["effectline"]["effectline"][effectlineIndex].contains(EFFECTLINE_ID[infoIndex])) {
242             for (size_t idIndex = 0;
243                 idIndex < newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_ID[infoIndex]].size();
244                 idIndex++) {
245                 int32_t oldFileId =
246                     newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_ID[infoIndex]][idIndex];
247                 newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_ID[infoIndex]][idIndex] =
248                     cloneHighlight.GetNewHighlightPhotoId(oldFileId);
249             }
250         }
251 
252         if (newPlayInfo["effectline"]["effectline"][effectlineIndex].contains(EFFECTLINE_URI[infoIndex])) {
253             for (size_t uriIndex = 0;
254                 uriIndex < newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_URI[infoIndex]].size();
255                 uriIndex++) {
256                 std::string oldFileUri =
257                     newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_URI[infoIndex]][uriIndex];
258                 newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_URI[infoIndex]][uriIndex] =
259                     GetNewPhotoUriByUri(oldFileUri, cloneHighlight);
260             }
261         }
262     }
263 }
264 
ParseTimeline(nlohmann::json & newPlayInfo,size_t timelineIndex,CloneRestoreHighlight & cloneHighlight)265 void CloneRestoreCVAnalysis::ParseTimeline(nlohmann::json &newPlayInfo, size_t timelineIndex,
266     CloneRestoreHighlight &cloneHighlight)
267 {
268     if (newPlayInfo["timeline"][timelineIndex].contains("effectVideoUri")) {
269         std::string oldEffectVideoUri = newPlayInfo["timeline"][timelineIndex]["effectVideoUri"];
270         newPlayInfo["timeline"][timelineIndex]["effectVideoUri"] = GetValueFromMap(assetUriMap_, oldEffectVideoUri);
271     }
272 
273     if (newPlayInfo["timeline"][timelineIndex].contains("transitionVideoUri")) {
274         std::string oldTransVideoUri = newPlayInfo["timeline"][timelineIndex]["transitionVideoUri"];
275         newPlayInfo["timeline"][timelineIndex]["transitionVideoUri"] = GetValueFromMap(assetUriMap_, oldTransVideoUri);
276     }
277 
278     if (newPlayInfo["timeline"][timelineIndex].contains("fileId")) {
279         for (size_t idIndex = 0; idIndex < newPlayInfo["timeline"][timelineIndex]["fileId"].size(); idIndex++) {
280             int32_t oldFileId = newPlayInfo["timeline"][timelineIndex]["fileId"][idIndex];
281             newPlayInfo["timeline"][timelineIndex]["fileId"][idIndex] =
282                 cloneHighlight.GetNewHighlightPhotoId(oldFileId);
283         }
284     }
285 
286     if (newPlayInfo["timeline"][timelineIndex].contains("fileUri")) {
287         for (size_t uriIndex = 0; uriIndex < newPlayInfo["timeline"][timelineIndex]["fileUri"].size(); uriIndex++) {
288             std::string oldFileUri = newPlayInfo["timeline"][timelineIndex]["fileUri"][uriIndex];
289             newPlayInfo["timeline"][timelineIndex]["fileUri"][uriIndex] =
290                 GetNewPhotoUriByUri(oldFileUri, cloneHighlight);
291         }
292     }
293 }
294 
GetNewEffectVideoUri(const std::string & oldVideoUri,CloneRestoreHighlight & cloneHighlight)295 std::string CloneRestoreCVAnalysis::GetNewEffectVideoUri(const std::string &oldVideoUri,
296     CloneRestoreHighlight &cloneHighlight)
297 {
298     CHECK_AND_RETURN_RET(assetUriMap_.find(oldVideoUri) == assetUriMap_.end(), assetUriMap_.at(oldVideoUri));
299     CHECK_AND_RETURN_RET(oldVideoUri != "", "");
300     size_t rightIndex = oldVideoUri.rfind("/");
301     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
302     size_t leftIndex = oldVideoUri.rfind("/", rightIndex - 1);
303     CHECK_AND_RETURN_RET(leftIndex != std::string::npos && rightIndex > leftIndex + 1, "");
304     int32_t oldAssetId = std::atoi((oldVideoUri.substr(leftIndex + 1, rightIndex - leftIndex - 1)).c_str());
305     int32_t newAssetId = cloneHighlight.GetNewHighlightPhotoId(oldAssetId);
306 
307     size_t suffixLeftIndex = oldVideoUri.find("_", rightIndex);
308     CHECK_AND_RETURN_RET(suffixLeftIndex != std::string::npos, "");
309     size_t suffixRightIndex = oldVideoUri.find("?", suffixLeftIndex);
310     CHECK_AND_RETURN_RET(suffixRightIndex != std::string::npos && suffixRightIndex > suffixLeftIndex, "");
311     std::string suffix = oldVideoUri.substr(suffixLeftIndex, suffixRightIndex - suffixLeftIndex);
312     std::string newVideoUri = HIGHLIGHT_ASSET_URI_PREFIX + std::to_string(newAssetId)
313         + "/" + std::to_string(newAssetId) + suffix + HIGHLIGHT_ASSET_URI_SUFFIX;
314 
315     assetUriMap_.insert(std::make_pair(oldVideoUri, newVideoUri));
316     std::string dstPath = "/storage/media/local/files/highlight/video/" + std::to_string(newAssetId) + "/" +
317         std::to_string(newAssetId) + suffix;
318     std::string srcPath = assetPath_ + std::to_string(oldAssetId) + "/" + std::to_string(oldAssetId) + suffix;
319     MoveAnalysisAssets(srcPath, dstPath);
320     return newVideoUri;
321 }
322 
GetNewTransitionVideoUri(const std::string & oldVideoUri,CloneRestoreHighlight & cloneHighlight)323 std::string CloneRestoreCVAnalysis::GetNewTransitionVideoUri(const std::string &oldVideoUri,
324     CloneRestoreHighlight &cloneHighlight)
325 {
326     CHECK_AND_RETURN_RET(assetUriMap_.find(oldVideoUri) == assetUriMap_.end(), assetUriMap_.at(oldVideoUri));
327     CHECK_AND_RETURN_RET(oldVideoUri != "", "");
328     size_t rightIndex = oldVideoUri.rfind("/");
329     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
330     size_t leftIndex = oldVideoUri.rfind("/", rightIndex - 1);
331     CHECK_AND_RETURN_RET(leftIndex != std::string::npos && rightIndex > leftIndex + 1, "");
332     int32_t oldAssetId = std::atoi((oldVideoUri.substr(leftIndex + 1, rightIndex - leftIndex - 1)).c_str());
333     int32_t newAssetId = cloneHighlight.GetNewHighlightPhotoId(oldAssetId);
334 
335     size_t secondLeftIndex = oldVideoUri.find("_", rightIndex);
336     CHECK_AND_RETURN_RET(secondLeftIndex != std::string::npos, "");
337     size_t secondRightIndex = oldVideoUri.find("_", secondLeftIndex + 1);
338     CHECK_AND_RETURN_RET(secondRightIndex != std::string::npos && secondRightIndex > secondLeftIndex + 1, "");
339     int32_t oldNextAssetId = std::atoi((oldVideoUri.substr(secondLeftIndex + 1,
340         secondRightIndex - secondLeftIndex - 1)).c_str());
341     int32_t newNextPhotoId = cloneHighlight.GetNewHighlightPhotoId(oldNextAssetId);
342 
343     size_t suffixRightIndex = oldVideoUri.find("?", secondRightIndex);
344     CHECK_AND_RETURN_RET(suffixRightIndex != std::string::npos && suffixRightIndex > secondRightIndex, "");
345     std::string suffix = oldVideoUri.substr(secondRightIndex, suffixRightIndex - secondRightIndex);
346 
347     std::string newVideoUri = HIGHLIGHT_ASSET_URI_PREFIX + std::to_string(newAssetId) + "/" +
348         std::to_string(newAssetId) + "_" + std::to_string(newNextPhotoId) + suffix + HIGHLIGHT_ASSET_URI_SUFFIX;
349     assetUriMap_.insert(std::make_pair(oldVideoUri, newVideoUri));
350 
351     std::string dstPath = "/storage/media/local/files/highlight/video/" + std::to_string(newAssetId) + "/" +
352         std::to_string(newAssetId) + "_" + std::to_string(newNextPhotoId) + suffix;
353     std::string srcPath = assetPath_ + std::to_string(oldAssetId) + "/" +
354         std::to_string(oldAssetId) + "_" + std::to_string(oldNextAssetId) + suffix;
355     MoveAnalysisAssets(srcPath, dstPath);
356     return newVideoUri;
357 }
358 
GetNewPhotoUriByUri(const std::string & oldUri,CloneRestoreHighlight & cloneHighlight)359 std::string CloneRestoreCVAnalysis::GetNewPhotoUriByUri(const std::string &oldUri,
360     CloneRestoreHighlight &cloneHighlight)
361 {
362     CHECK_AND_RETURN_RET(assetUriMap_.find(oldUri) == assetUriMap_.end(), assetUriMap_.at(oldUri));
363     CHECK_AND_RETURN_RET(oldUri != "", "");
364     size_t rightIndex = oldUri.rfind("/");
365     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
366     size_t suffixIndex = oldUri.find("?", rightIndex);
367     rightIndex = oldUri.rfind("/", rightIndex - 1);
368     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
369     size_t leftIndex = oldUri.rfind("/", rightIndex - 1);
370     CHECK_AND_RETURN_RET(leftIndex != std::string::npos && rightIndex > leftIndex + 1, "");
371 
372     int32_t oldPhotoId = std::atoi((oldUri.substr(leftIndex + 1, rightIndex - leftIndex - 1)).c_str());
373     std::string newUri = cloneHighlight.GetNewHighlightPhotoUri(oldPhotoId);
374 
375     CHECK_AND_EXECUTE(suffixIndex == std::string::npos, newUri += oldUri.substr(suffixIndex));
376     assetUriMap_.insert(std::make_pair(oldUri, newUri));
377     return newUri;
378 }
379 
MoveAnalysisAssets(const std::string & srcPath,const std::string & dstPath)380 void CloneRestoreCVAnalysis::MoveAnalysisAssets(const std::string &srcPath, const std::string &dstPath)
381 {
382     std::string srcGarble = srcPath;
383     srcGarble.replace(0, assetPath_.length(), "*/");
384     std::string dstGarble = MediaFileUtils::DesensitizePath(dstPath);
385     CHECK_AND_RETURN_LOG(MediaFileUtils::IsFileExists(srcPath), "src file doesn't exist, srcPath:%{public}s."
386         "dstPath:%{public}s", srcGarble.c_str(), dstGarble.c_str());
387     CHECK_AND_RETURN_INFO_LOG(!MediaFileUtils::IsFileExists(dstPath),
388         "dst file already exists, srcPath:%{public}s, dstPath:%{public}s.", srcGarble.c_str(), dstGarble.c_str());
389     int32_t errCode = BackupFileUtils::PreparePath(dstPath);
390     CHECK_AND_RETURN_LOG(errCode == E_OK, "PreparePath failed, can't move file, srcPath:%{public}s, "
391         "dstPath:%{public}s, errcode:%{public}d", srcGarble.c_str(), dstGarble.c_str(), errCode);
392     errCode = BackupFileUtils::MoveFile(srcPath, dstPath, sceneCode_);
393     CHECK_AND_RETURN_LOG(errCode == E_OK, "move file failed, srcPath:%{public}s, dstPath:%{public}s, "
394         "errcode:%{public}d", srcGarble.c_str(), dstGarble.c_str(), errCode);
395     MEDIA_INFO_LOG("move file successed, srcPath:%{public}s, dstPath:%{public}s", srcGarble.c_str(), dstGarble.c_str());
396 }
397 
UpdateHighlightPlayInfos(CloneRestoreHighlight & cloneHighlight,std::vector<int32_t> & updateHighlightIds)398 void CloneRestoreCVAnalysis::UpdateHighlightPlayInfos(CloneRestoreHighlight &cloneHighlight,
399     std::vector<int32_t> &updateHighlightIds)
400 {
401     int32_t rowCount = 0;
402     int32_t offset = 0;
403     std::string defaultPlayInfo = cloneHighlight.GetDefaultPlayInfo();
404     do {
405         const std::string QUERY_SQL = "SELECT p.album_id, p.play_info_id, p.play_info FROM tab_highlight_play_info AS p"
406             " INNER JOIN tab_highlight_album AS h ON p.album_id = h.id WHERE h.highlight_status > 0 "
407             " LIMIT " + std::to_string(offset) + ", " + std::to_string(PAGE_SIZE);
408         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
409         CHECK_AND_RETURN_INFO_LOG(resultSet != nullptr, "query resultSql is null.");
410 
411         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
412             std::optional<int32_t> oldAlbumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "p.album_id");
413             CHECK_AND_CONTINUE(oldAlbumId.has_value());
414             std::optional<int32_t> playId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "p.play_info_id");
415             std::optional<std::string> oldPlayInfo =
416                 BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, "p.play_info");
417             std::string newPlayInfo = defaultPlayInfo;
418             CHECK_AND_EXECUTE(!oldPlayInfo.has_value(),
419                 newPlayInfo = ParsePlayInfo(oldPlayInfo.value(), cloneHighlight));
420 
421             int32_t albumId = cloneHighlight.GetNewHighlightAlbumId(oldAlbumId.value());
422             std::string updatePlayInfoSql = "UPDATE tab_highlight_play_info SET play_info = ? WHERE album_id = ? ";
423             int32_t ret = E_ERR;
424             if (playId.has_value()) {
425                 std::string playInfoId = std::to_string(playId.value());
426                 updatePlayInfoSql += "AND play_info_id = ?";
427                 ret = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, updatePlayInfoSql,
428                     { newPlayInfo, albumId, playInfoId });
429             } else {
430                 updatePlayInfoSql += "AND play_info_id ISNULL";
431                 ret = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, updatePlayInfoSql,
432                     { newPlayInfo, albumId });
433             }
434             bool successfulParseCond = (newPlayInfo != defaultPlayInfo && ret == E_OK) ||
435                 (newPlayInfo == defaultPlayInfo && oldPlayInfo == defaultPlayInfo);
436             if (successfulParseCond) {
437                 updateHighlightIds.emplace_back(albumId);
438                 continue;
439             }
440             CHECK_AND_PRINT_LOG(ret == E_OK, "Update play_info Sql err, highlight id: %{public}d, errCode: %{public}d",
441                 albumId, ret);
442             ErrorInfo errorInfo(RestoreError::UPDATE_FAILED, 0, std::to_string(ret),
443                 "Update play_info failed. highlight id:" + std::to_string(albumId));
444             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
445         }
446         resultSet->GetRowCount(rowCount);
447         offset += PAGE_SIZE;
448         resultSet->Close();
449     } while (rowCount == PAGE_SIZE);
450 }
451 
ReportCloneRestoreCVAnalysisTask()452 void CloneRestoreCVAnalysis::ReportCloneRestoreCVAnalysisTask()
453 {
454     std::stringstream totalReport;
455     totalReport << "isHighlightVideoDirExist: " << isHighlightVideoDirExist_ << ", timeCost: " << restoreTimeCost_ <<
456         "; ASSET_SD: success: " << assetSdSuccessCnt_ << ", failed: " << assetSdFailedCnt_ <<
457         "; ALBUM_ASSET: success: " << albumAssetSuccessCnt_ << ", failed: " << albumAssetFailedCnt_;
458     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
459         .Report("CLONE_RESTORE_CV_ANALYSIS_TOTAL", RESTORE_STATUS_SUCCESS, totalReport.str());
460 }
461 } // namespace OHOS::Media