• 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 "MediaLibraryCloneRestoreHighlight"
17 
18 #include "clone_restore_highlight.h"
19 
20 #include "backup_file_utils.h"
21 #include "medialibrary_data_manager_utils.h"
22 #include "media_file_utils.h"
23 #include "upgrade_restore_task_report.h"
24 
25 namespace OHOS::Media {
26 const int32_t PAGE_SIZE = 200;
27 const std::vector<std::string> HIGHLIGHT_RATIO_WORD_ART = { "1_1", "3_2", "3_4", "microcard", "medium_card",
28     "big_card", "screen_0_ver", "screen_0_hor" };
29 const std::vector<std::string> HIGHLIGHT_COVER_NAME = { "foreground", "background" };
30 const std::string MUSIC_DIR_DST_PATH = "/storage/media/local/files/highlight/music";
31 const std::string GARBLE_DST_PATH = "/storage/media/local/files";
32 const int32_t HIGHLIGHT_STATUS_NOT_PRODUCE = -1;
33 const int32_t HIGHLIGHT_STATUS_DELETE = -4;
34 const std::string RESTORE_STATUS_SUCCESS = "1";
35 
36 const std::unordered_map<std::string, std::unordered_set<std::string>> ALBUM_COLUMNS_MAP = {
37     { "AnalysisAlbum",
38         {
39             "album_id",
40             "album_type",
41             "album_subtype",
42             "album_name",
43             "cover_uri",
44             "count",
45             "date_modified",
46             "rank",
47             "tag_id",
48             "user_operation",
49             "group_tag",
50             "user_display_level",
51             "is_me",
52             "is_removed",
53             "rename_operation",
54             "is_local",
55             "is_cover_satisfied",
56             "relationship"
57         }
58     },
59     { "AnalysisPhotoMap",
60         {
61             "map_album",
62             "map_asset",
63             "order_position"
64         }
65     },
66     { "tab_highlight_album",
67         {
68             "id",
69             "album_id",
70             "ai_album_id",
71             "sub_title",
72             "cluster_type",
73             "cluster_sub_type",
74             "cluster_condition",
75             "min_date_added",
76             "max_date_added",
77             "generate_time",
78             "highlight_version",
79             "remarks",
80             "highlight_status",
81             "insert_pic_count",
82             "remove_pic_count",
83             "share_screenshot_count",
84             "share_cover_count",
85             "rename_count",
86             "change_cover_count",
87             "render_viewed_times",
88             "render_viewed_duration",
89             "art_layout_viewed_times",
90             "art_layout_viewed_duration",
91             "music_edit_count",
92             "filter_edit_count",
93             "is_muted",
94             "is_favorite",
95             "theme",
96             "pin_time",
97             "use_subtitle",
98             "highlight_location"
99         }
100     },
101     { "tab_highlight_cover_info",
102         {
103             "album_id",
104             "ratio",
105             "background",
106             "foreground",
107             "wordart",
108             "is_covered",
109             "color",
110             "radius",
111             "saturation",
112             "brightness",
113             "background_color_type",
114             "shadow_level",
115             "title_scale_x",
116             "title_scale_y",
117             "title_rect_width",
118             "title_rect_height",
119             "background_scale_x",
120             "background_scale_y",
121             "background_rect_width",
122             "background_rect_height",
123             "is_chosen",
124             "layout_index",
125             "cover_algo_version",
126             "cover_service_version",
127             "cover_key",
128             "status"
129         }
130     },
131     { "tab_highlight_play_info",
132         {
133             "album_id",
134             "music",
135             "filter",
136             "play_info",
137             "is_chosen",
138             "play_info_version",
139             "play_info_id",
140             "highlighting_algo_version",
141             "camera_movement_algo_version",
142             "transition_algo_version",
143             "play_service_version",
144             "status"
145         }
146     }
147 };
148 
149 template<typename Key, typename Value>
GetValueFromMap(const std::unordered_map<Key,Value> & map,const Key & key,const Value & defaultValue=Value ())150 Value GetValueFromMap(const std::unordered_map<Key, Value> &map, const Key &key, const Value &defaultValue = Value())
151 {
152     auto it = map.find(key);
153     CHECK_AND_RETURN_RET(it != map.end(), defaultValue);
154     return it->second;
155 }
156 
Init(const InitInfo & info)157 void CloneRestoreHighlight::Init(const InitInfo &info)
158 {
159     sceneCode_ = info.sceneCode;
160     taskId_ = info.taskId;
161     mediaLibraryRdb_ = info.mediaLibraryRdb;
162     mediaRdb_ = info.mediaRdb;
163 
164     std::string highlightSourcePath = info.backupRestoreDir + "/storage/media/local/files/highlight/";
165     isHighlightDirExist_ = MediaFileUtils::IsDirectory(highlightSourcePath);
166     MEDIA_INFO_LOG("/highlight/ source dir %{public}s.", isHighlightDirExist_ ? "exist" : "don't exist");
167     coverPath_ = highlightSourcePath + "cover/";
168     musicDir_ = highlightSourcePath + "music";
169     garblePath_ = info.backupRestoreDir + GARBLE_DST_PATH;
170 
171     photoInfoMap_ = info.photoInfoMap;
172 }
173 
Restore()174 void CloneRestoreHighlight::Restore()
175 {
176     int64_t startPreprocess = MediaFileUtils::UTCTimeMilliSeconds();
177     Preprocess();
178     int64_t startRestoreAlbums = MediaFileUtils::UTCTimeMilliSeconds();
179     RestoreAlbums();
180     int64_t startRestoreMaps = MediaFileUtils::UTCTimeMilliSeconds();
181     RestoreMaps();
182     int64_t startUpdateAlbums = MediaFileUtils::UTCTimeMilliSeconds();
183     UpdateAlbums();
184     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
185     restoreTimeCost_ += end - startPreprocess;
186     MEDIA_INFO_LOG("TimeCost: Preprocess: %{public}" PRId64 ",RestoreAlbums: %{public}" PRId64
187         ", RestoreMaps: %{public}" PRId64 ", UpdateAlbums: %{public}" PRId64, startRestoreAlbums - startPreprocess,
188         startRestoreMaps - startRestoreAlbums, startUpdateAlbums - startRestoreMaps, end - startUpdateAlbums);
189 }
190 
Preprocess()191 void CloneRestoreHighlight::Preprocess()
192 {
193     CHECK_AND_RETURN_LOG(mediaRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr.");
194     const std::vector<std::string> SQLS = {
195         "ALTER TABLE AnalysisAlbum ADD COLUMN need_restore_highlight INTEGER DEFAULT 0 ",
196         "UPDATE AnalysisAlbum SET need_restore_highlight = 1 "
197             " WHERE album_id IN (SELECT album_id FROM tab_highlight_album WHERE highlight_status > 0 "
198             " UNION SELECT ai_album_id FROM tab_highlight_album WHERE highlight_status > 0) ",
199         "CREATE INDEX idx_need_restore_highlight ON AnalysisAlbum(need_restore_highlight) "
200             " WHERE need_restore_highlight = 1 ",
201     };
202     for (const auto &sql : SQLS) {
203         int32_t errCode = BackupDatabaseUtils::ExecuteSQL(mediaRdb_, sql);
204         if (errCode != NativeRdb::E_OK) {
205             MEDIA_ERR_LOG("Execute %{public}s failed, errCode: %{public}d", sql.c_str(), errCode);
206             ErrorInfo errorInfo(RestoreError::INIT_FAILED, 0, std::to_string(errCode),
207                 "clone restore highlight preprocess failed");
208             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
209             return;
210         }
211     }
212     isCloneHighlight_ = true;
213 }
214 
RestoreAlbums()215 void CloneRestoreHighlight::RestoreAlbums()
216 {
217     CHECK_AND_RETURN_LOG(isCloneHighlight_, "clone highlight flag is false.");
218     MEDIA_INFO_LOG("restore highlight album start.");
219     isMapOrder_ = IsMapColumnOrderExist();
220     GetAnalysisAlbumInfos();
221     InsertIntoAnalysisAlbum();
222     GetHighlightAlbumInfos();
223     InsertIntoHighlightAlbum();
224     MoveHighlightCovers();
225     MoveHighlightMusic(musicDir_, MUSIC_DIR_DST_PATH);
226     GetHighlightCoverInfos();
227     InsertIntoHighlightCoverInfo();
228     GetHighlightPlayInfos();
229     InsertIntoHighlightPlayInfo();
230 }
231 
RestoreMaps()232 void CloneRestoreHighlight::RestoreMaps()
233 {
234     CHECK_AND_RETURN_LOG(isCloneHighlight_, "clone highlight flag is false.");
235     MEDIA_INFO_LOG("restore highlight map start.");
236     int32_t totalNumber = GetTotalNumberOfMaps();
237     MEDIA_INFO_LOG("totalNumber: %{public}d", totalNumber);
238     for (int32_t offset = 0; offset < totalNumber; offset += PAGE_SIZE) {
239         RestoreMapsBatch();
240     }
241 }
242 
GetTotalNumberOfMaps()243 int32_t CloneRestoreHighlight::GetTotalNumberOfMaps()
244 {
245     const std::string QUERY_SQL = "SELECT count(1) AS count FROM AnalysisPhotoMap AS map "
246         " INNER JOIN AnalysisAlbum AS a ON map.map_album = a.album_id "
247         " WHERE a.album_subtype IN (4104, 4105) AND a.need_restore_highlight = 1 ";
248     return BackupDatabaseUtils::QueryInt(mediaRdb_, QUERY_SQL, "count");
249 }
250 
RestoreMapsBatch()251 void CloneRestoreHighlight::RestoreMapsBatch()
252 {
253     std::vector<NativeRdb::ValuesBucket> values;
254     int64_t startUpdateTime = MediaFileUtils::UTCTimeMilliSeconds();
255     UpdateMapInsertValues(values);
256     int64_t startInsertTime = MediaFileUtils::UTCTimeMilliSeconds();
257     InsertAnalysisPhotoMap(values);
258     int64_t endTime = MediaFileUtils::UTCTimeMilliSeconds();
259     MEDIA_INFO_LOG("TimeCost: UpdateMapInsertValues: %{public}" PRId64 ", InsertAnalysisPhotoMap: %{public}" PRId64,
260         startInsertTime - startUpdateTime, endTime - startInsertTime);
261 }
262 
UpdateAlbums()263 void CloneRestoreHighlight::UpdateAlbums()
264 {
265     CHECK_AND_RETURN_LOG(isCloneHighlight_, "clone highlight flag is false.");
266     MEDIA_INFO_LOG("update highlight album start.");
267     const std::string UPDATE_ALBUM_SQL = "UPDATE AnalysisAlbum SET "
268         "cover_uri = ?, "
269         "count = (SELECT count(1) FROM AnalysisPhotoMap AS apm WHERE apm.map_album = AnalysisAlbum.album_id) "
270         "WHERE album_id = ?";
271     for (const auto &info : analysisInfos_) {
272         bool cond = (!info.oldCoverUri.has_value() || !info.albumIdNew.has_value());
273         CHECK_AND_CONTINUE(!cond);
274         BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_ALBUM_SQL, { info.coverUri,
275             info.albumIdNew.value() });
276     }
277 
278     const std::string UPDATE_COVER_KEY_SQL = "UPDATE tab_highlight_cover_info SET cover_key = ? "
279         "WHERE album_id = ? AND ratio = ?";
280     for (const auto &coverInfo : coverInfos_) {
281         bool cond = (!coverInfo.ratio.has_value() || !coverInfo.highlightIdNew.has_value());
282         CHECK_AND_CONTINUE(!cond);
283         auto it = std::find_if(analysisInfos_.begin(), analysisInfos_.end(),
284             [coverInfo](const AnalysisAlbumInfo& info) { return info.highlightIdNew == coverInfo.highlightIdNew; });
285         cond = (it == analysisInfos_.end() || !it->albumName.has_value());
286         CHECK_AND_CONTINUE(!cond);
287         std::string coverUri = it->albumName.value() + "_" + coverInfo.ratio.value() + "_" + it->coverUri;
288         BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_COVER_KEY_SQL, { coverUri,
289             coverInfo.highlightIdNew.value(), coverInfo.ratio.value()});
290     }
291 }
292 
GetNewHighlightAlbumId(int32_t oldId)293 int32_t CloneRestoreHighlight::GetNewHighlightAlbumId(int32_t oldId)
294 {
295     int32_t newId = -1;
296     auto it = std::find_if(highlightInfos_.begin(), highlightInfos_.end(),
297         [oldId](const HighlightAlbumInfo& info) { return info.highlightIdOld == oldId; });
298     bool cond = (it != highlightInfos_.end() && it->highlightIdNew.has_value());
299     CHECK_AND_EXECUTE(!cond, newId = it->highlightIdNew.value());
300     return newId;
301 }
302 
GetNewHighlightPhotoId(int32_t oldId)303 int32_t CloneRestoreHighlight::GetNewHighlightPhotoId(int32_t oldId)
304 {
305     auto it = photoInfoMap_.find(oldId);
306     if (it == photoInfoMap_.end()) {
307         return 0;
308     }
309     return it->second.fileIdNew;
310 }
311 
GetNewHighlightPhotoUri(int32_t oldId)312 std::string CloneRestoreHighlight::GetNewHighlightPhotoUri(int32_t oldId)
313 {
314     auto it = photoInfoMap_.find(oldId);
315     if (it == photoInfoMap_.end()) {
316         return "";
317     }
318     PhotoInfo photoInfo = it->second;
319     return MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
320         std::to_string(photoInfo.fileIdNew), MediaFileUtils::GetExtraUri(photoInfo.displayName, photoInfo.cloudPath));
321 }
322 
IsCloneHighlight()323 bool CloneRestoreHighlight::IsCloneHighlight()
324 {
325     return isCloneHighlight_;
326 }
327 
GetDefaultPlayInfo()328 std::string CloneRestoreHighlight::GetDefaultPlayInfo()
329 {
330     nlohmann::json playInfo;
331     playInfo["beatsInfo"] = nlohmann::json::array();
332     playInfo["effectline"] = nlohmann::json::object();
333     playInfo["effectline"]["effectline"] = nlohmann::json::array();
334     playInfo["timeline"] = nlohmann::json::array();
335     return playInfo.dump();
336 }
337 
UpdateHighlightStatus(const std::vector<int32_t> & highlightIds)338 void CloneRestoreHighlight::UpdateHighlightStatus(const std::vector<int32_t> &highlightIds)
339 {
340     std::unordered_map<int32_t, std::vector<NativeRdb::ValueObject>> highlightStatusMap;
341     for (auto highlightId : highlightIds) {
342         auto it = std::find_if(highlightInfos_.begin(), highlightInfos_.end(),
343         [highlightId](const HighlightAlbumInfo &highlightInfo) {
344             return highlightInfo.highlightIdNew.has_value() && highlightInfo.highlightIdNew.value() == highlightId &&
345                 highlightInfo.highlightStatus.has_value() && highlightInfo.highlightStatus.value() > 0;
346         });
347         CHECK_AND_CONTINUE(it != highlightInfos_.end());
348         UpdateHighlightStatusMap(it->highlightStatus.value(), highlightId, highlightStatusMap);
349     }
350     UpdateHighlightStatusInDatabase(highlightStatusMap);
351 }
352 
UpdateHighlightStatusMap(int32_t highlightStatus,int32_t highlightId,std::unordered_map<int32_t,std::vector<NativeRdb::ValueObject>> & highlightStatusMap)353 void CloneRestoreHighlight::UpdateHighlightStatusMap(int32_t highlightStatus, int32_t highlightId,
354     std::unordered_map<int32_t, std::vector<NativeRdb::ValueObject>> &highlightStatusMap)
355 {
356     std::vector<NativeRdb::ValueObject> &highlightIds = highlightStatusMap[highlightStatus];
357     highlightIds.emplace_back(highlightId);
358 }
359 
UpdateHighlightStatusInDatabase(const std::unordered_map<int32_t,std::vector<NativeRdb::ValueObject>> & highlightStatusMap)360 void CloneRestoreHighlight::UpdateHighlightStatusInDatabase(
361     const std::unordered_map<int32_t, std::vector<NativeRdb::ValueObject>> &highlightStatusMap)
362 {
363     CHECK_AND_RETURN(!highlightStatusMap.empty());
364     for (const auto &[highlightStatus, highlightIds] : highlightStatusMap) {
365         int32_t changedRows = -1;
366         std::unique_ptr<NativeRdb::AbsRdbPredicates> updatePredicates =
367             make_unique<NativeRdb::AbsRdbPredicates>("tab_highlight_album");
368         updatePredicates->In("id", highlightIds);
369         NativeRdb::ValuesBucket rdbValues;
370         rdbValues.PutInt("highlight_status", highlightStatus);
371         int32_t errCode = BackupDatabaseUtils::Update(mediaLibraryRdb_, changedRows, rdbValues, updatePredicates);
372         std::stringstream updateReport;
373         updateReport << "highlightStatus: " << highlightStatus << ", to be pushed: " << highlightIds.size() <<
374             ", update: " << changedRows;
375         UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
376             .Report("CLONE_RESTORE_HIGHLIGHT_STATUS", std::to_string(errCode), updateReport.str());
377     }
378 }
379 
GetMaxAlbumId(const std::string & tableName,const std::string & idName)380 int32_t CloneRestoreHighlight::GetMaxAlbumId(const std::string &tableName, const std::string &idName)
381 {
382     int32_t maxAlbumId = 1;
383     const std::string QUERY_SQL = "SELECT MAX(" + idName + ") " + idName + " FROM " + tableName;
384     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, QUERY_SQL);
385     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, -1, "query resultSql is null.");
386     if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
387         auto albumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, idName);
388         CHECK_AND_EXECUTE(!albumId.has_value(), maxAlbumId = albumId.value() + 1);
389     }
390     resultSet->Close();
391     return maxAlbumId;
392 }
393 
IsMapColumnOrderExist()394 bool CloneRestoreHighlight::IsMapColumnOrderExist()
395 {
396     bool result = false;
397     std::unordered_set<std::string> intersection = GetCommonColumns("AnalysisPhotoMap");
398     CHECK_AND_EXECUTE(intersection.count("order_position") <= 0, result = true);
399     return result;
400 }
401 
GetAnalysisAlbumInfos()402 void CloneRestoreHighlight::GetAnalysisAlbumInfos()
403 {
404     int32_t albumIdNow = GetMaxAlbumId("AnalysisAlbum", "album_id");
405     maxIdOfAlbum_ = albumIdNow;
406     int32_t rowCount = 0;
407     int32_t offset = 0;
408     do {
409         const std::string QUERY_SQL = "SELECT * FROM AnalysisAlbum "
410             " WHERE album_subtype IN (4104, 4105) AND need_restore_highlight = 1 "
411             " LIMIT " + std::to_string(offset) + ", " + std::to_string(PAGE_SIZE);
412         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
413         CHECK_AND_BREAK_INFO_LOG(resultSet != nullptr, "query resultSql is null.");
414         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
415             AnalysisAlbumInfo info;
416             GetAnalysisRowInfo(info, resultSet);
417             info.albumIdNew = std::make_optional<int32_t>(albumIdNow++);
418             analysisInfos_.emplace_back(info);
419         }
420         resultSet->GetRowCount(rowCount);
421         offset += PAGE_SIZE;
422         resultSet->Close();
423     } while (rowCount == PAGE_SIZE);
424     MEDIA_INFO_LOG("query AnalysisAlbum nums: %{public}zu", analysisInfos_.size());
425 }
426 
GetAnalysisRowInfo(AnalysisAlbumInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)427 void CloneRestoreHighlight::GetAnalysisRowInfo(AnalysisAlbumInfo &info, std::shared_ptr<NativeRdb::ResultSet> resultSet)
428 {
429     if (intersectionMap_.find("AnalysisAlbum") == intersectionMap_.end()) {
430         intersectionMap_.insert(std::make_pair("AnalysisAlbum", GetCommonColumns("AnalysisAlbum")));
431     }
432     std::unordered_set<std::string>& intersection = intersectionMap_["AnalysisAlbum"];
433     GetIfInIntersection("album_id", info.albumIdOld, intersection, resultSet);
434     GetIfInIntersection("album_type", info.albumType, intersection, resultSet);
435     GetIfInIntersection("album_subtype", info.albumSubtype, intersection, resultSet);
436     GetIfInIntersection("album_name", info.albumName, intersection, resultSet);
437     GetIfInIntersection("cover_uri", info.oldCoverUri, intersection, resultSet);
438     GetIfInIntersection("date_modified", info.dateModified, intersection, resultSet);
439     GetIfInIntersection("rank", info.rank, intersection, resultSet);
440     GetIfInIntersection("tag_id", info.tagId, intersection, resultSet);
441     GetIfInIntersection("user_operation", info.userOperation, intersection, resultSet);
442     GetIfInIntersection("group_tag", info.groupTag, intersection, resultSet);
443     GetIfInIntersection("user_display_level", info.userDisplayLevel, intersection, resultSet);
444     GetIfInIntersection("is_me", info.isMe, intersection, resultSet);
445     GetIfInIntersection("is_removed", info.isRemoved, intersection, resultSet);
446     GetIfInIntersection("rename_operation", info.renameOperation, intersection, resultSet);
447     GetIfInIntersection("is_local", info.isLocal, intersection, resultSet);
448     GetIfInIntersection("is_cover_satisfied", info.isCoverSatisfied, intersection, resultSet);
449     GetIfInIntersection("relationship", info.relationship, intersection, resultSet);
450     UpdateAlbumCoverUri(info);
451 }
452 
UpdateAlbumCoverUri(AnalysisAlbumInfo & info)453 void CloneRestoreHighlight::UpdateAlbumCoverUri(AnalysisAlbumInfo &info)
454 {
455     std::string fileIdOldStr = MediaFileUtils::GetIdFromUri(info.oldCoverUri.value_or(""));
456     CHECK_AND_RETURN(!fileIdOldStr.empty() && MediaLibraryDataManagerUtils::IsNumber(fileIdOldStr));
457     int32_t fileIdOld = std::atoi(fileIdOldStr.c_str());
458     info.coverUri = GetNewHighlightPhotoUri(fileIdOld);
459     MEDIA_INFO_LOG("oldCoverUri: %{public}s, newCoverUri: %{public}s.",
460         BackupFileUtils::GarbleFilePath(info.oldCoverUri.value_or(""), DEFAULT_RESTORE_ID).c_str(),
461         BackupFileUtils::GarbleFilePath(info.coverUri, DEFAULT_RESTORE_ID).c_str());
462 }
463 
InsertIntoAnalysisAlbum()464 void CloneRestoreHighlight::InsertIntoAnalysisAlbum()
465 {
466     size_t offset = 0;
467     do {
468         std::vector<NativeRdb::ValuesBucket> values;
469         for (size_t index = 0; index < PAGE_SIZE && index + offset < analysisInfos_.size(); index++) {
470             NativeRdb::ValuesBucket value;
471             GetAnalysisInsertValue(value, analysisInfos_[index + offset]);
472             values.emplace_back(value);
473         }
474         int64_t rowNum = 0;
475         int32_t errCode = BatchInsertWithRetry("AnalysisAlbum", values, rowNum);
476         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
477             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
478             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
479                 "insert into AnalysisAlbum fail, num:" + std::to_string(failNums));
480             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
481             albumFailedCnt_ += failNums;
482         }
483         albumSuccessCnt_ += rowNum;
484         offset += PAGE_SIZE;
485     } while (offset < analysisInfos_.size());
486 }
487 
GetAnalysisInsertValue(NativeRdb::ValuesBucket & value,const AnalysisAlbumInfo & info)488 void CloneRestoreHighlight::GetAnalysisInsertValue(NativeRdb::ValuesBucket &value, const AnalysisAlbumInfo &info)
489 {
490     std::unordered_set<std::string>& intersection = intersectionMap_["AnalysisAlbum"];
491     PutIfInIntersection(value, "album_id", info.albumIdNew, intersection);
492     PutIfInIntersection(value, "album_type", info.albumType, intersection);
493     PutIfInIntersection(value, "album_subtype", info.albumSubtype, intersection);
494     PutIfInIntersection(value, "album_name", info.albumName, intersection);
495     PutIfInIntersection(value, "date_modified", info.dateModified, intersection);
496     PutIfInIntersection(value, "rank", info.rank, intersection);
497     PutIfInIntersection(value, "tag_id", info.tagId, intersection);
498     PutIfInIntersection(value, "user_operation", info.userOperation, intersection);
499     PutIfInIntersection(value, "group_tag", info.groupTag, intersection);
500     PutIfInIntersection(value, "user_display_level", info.userDisplayLevel, intersection);
501     PutIfInIntersection(value, "is_me", info.isMe, intersection);
502     PutIfInIntersection(value, "is_removed", info.isRemoved, intersection);
503     PutIfInIntersection(value, "rename_operation", info.renameOperation, intersection);
504     PutIfInIntersection(value, "is_local", info.isLocal, intersection);
505     PutIfInIntersection(value, "is_cover_satisfied", info.isCoverSatisfied, intersection);
506     PutIfInIntersection(value, "relationship", info.relationship, intersection);
507 }
508 
UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> & values)509 void CloneRestoreHighlight::UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> &values)
510 {
511     const std::string QUERY_SQL = "SELECT map.rowid, map.* FROM AnalysisPhotoMap AS map "
512         " INNER JOIN AnalysisAlbum AS a ON map.map_album = a.album_id "
513         " WHERE a.album_subtype IN (4104, 4105) AND a.need_restore_highlight = 1 "
514         " AND map.rowid > ? ORDER BY map.rowid LIMIT ? ";
515     std::vector<NativeRdb::ValueObject> params = { lastIdOfMap_, PAGE_SIZE };
516     auto resultSet = BackupDatabaseUtils::QuerySql(mediaRdb_, QUERY_SQL, params);
517     CHECK_AND_RETURN_LOG(resultSet != nullptr, "query AnalysisPhotoMap err!");
518     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
519         UpdateMapInsertValuesByAlbumId(values, resultSet);
520     }
521     resultSet->Close();
522 }
523 
UpdateMapInsertValuesByAlbumId(std::vector<NativeRdb::ValuesBucket> & values,std::shared_ptr<NativeRdb::ResultSet> resultSet)524 void CloneRestoreHighlight::UpdateMapInsertValuesByAlbumId(std::vector<NativeRdb::ValuesBucket> &values,
525     std::shared_ptr<NativeRdb::ResultSet> resultSet)
526 {
527     lastIdOfMap_ = GetInt32Val("rowid", resultSet);
528 
529     std::optional<int32_t> oldFileId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "map_asset");
530     bool exceptCond = oldFileId.has_value() && photoInfoMap_.count(oldFileId.value()) > 0;
531     CHECK_AND_RETURN_LOG(exceptCond, "the query oldFileId is invalid!");
532     PhotoInfo photoInfo = photoInfoMap_.at(oldFileId.value());
533 
534     std::optional<int32_t> oldAlbumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "map_album");
535     CHECK_AND_RETURN_LOG(oldAlbumId.has_value(), "the query oldAlbumId is invalid!");
536     auto it = std::find_if(analysisInfos_.begin(), analysisInfos_.end(),
537         [oldAlbumId](const AnalysisAlbumInfo& info) {
538             return info.albumIdOld.has_value() && info.albumIdOld.value() == oldAlbumId.value();
539         });
540     CHECK_AND_RETURN_LOG(it != analysisInfos_.end() && it->albumIdNew.has_value(),
541         "not find the needed album info, oldAlbumId: %{public}d", oldAlbumId.value());
542 
543     std::optional<int32_t> order = std::nullopt;
544     CHECK_AND_EXECUTE(!isMapOrder_,
545         order = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "order_position"));
546     values.emplace_back(GetMapInsertValue(it->albumIdNew.value(), photoInfo.fileIdNew, order));
547     std::lock_guard<mutex> lock(counterMutex_);
548     std::string reportAlbumName = std::to_string(it->albumIdNew.value());
549     CHECK_AND_EXECUTE(!it->albumName.has_value(), reportAlbumName += "_" + it->albumName.value());
550     CHECK_AND_EXECUTE(albumPhotoCounter_.count(reportAlbumName) != 0,
551         albumPhotoCounter_[reportAlbumName] = 0);
552     albumPhotoCounter_[reportAlbumName]++;
553 }
554 
InsertAnalysisPhotoMap(std::vector<NativeRdb::ValuesBucket> & values)555 void CloneRestoreHighlight::InsertAnalysisPhotoMap(std::vector<NativeRdb::ValuesBucket> &values)
556 {
557     int64_t rowNum = 0;
558     int32_t errCode = BatchInsertWithRetry("AnalysisPhotoMap", values, rowNum);
559     if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
560         int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
561         ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
562             "insert into AnalysisPhotoMap fail, num:" + std::to_string(failNums));
563         UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
564         mapFailedCnt_ += failNums;
565     }
566     mapSuccessCnt_ += rowNum;
567 }
568 
GetMapInsertValue(int32_t albumId,int32_t fileId,std::optional<int32_t> & order)569 NativeRdb::ValuesBucket CloneRestoreHighlight::GetMapInsertValue(int32_t albumId, int32_t fileId,
570     std::optional<int32_t> &order)
571 {
572     NativeRdb::ValuesBucket value;
573     value.PutInt("map_album", albumId);
574     value.PutInt("map_asset", fileId);
575     CHECK_AND_EXECUTE(!order.has_value(), value.PutInt("order_position", order.value()));
576     return value;
577 }
578 
BatchInsertWithRetry(const std::string & tableName,const std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)579 int32_t CloneRestoreHighlight::BatchInsertWithRetry(const std::string &tableName,
580     const std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
581 {
582     CHECK_AND_RETURN_RET(!values.empty(), 0);
583     int32_t errCode = E_ERR;
584     TransactionOperations trans{ __func__ };
585     trans.SetBackupRdbStore(mediaLibraryRdb_);
586     std::function<int(void)> func = [&]()->int {
587         errCode = trans.BatchInsert(rowNum, tableName, values);
588         CHECK_AND_PRINT_LOG(errCode == E_OK,
589             "InsertSql failed, errCode: %{public}d, rowNum: %{public}" PRId64, errCode, rowNum);
590         return errCode;
591     };
592     errCode = trans.RetryTrans(func, true);
593     CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
594     return errCode;
595 }
596 
GetHighlightAlbumInfos()597 void CloneRestoreHighlight::GetHighlightAlbumInfos()
598 {
599     int32_t idNow = GetMaxAlbumId("tab_highlight_album", "id");
600     maxIdOfHighlight_ = idNow;
601     int32_t rowCount = 0;
602     int32_t offset = 0;
603     do {
604         const std::string QUERY_SQL = "SELECT * FROM tab_highlight_album WHERE highlight_status > 0 "
605             " LIMIT " + std::to_string(offset) + ", " + std::to_string(PAGE_SIZE);
606         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
607         CHECK_AND_BREAK_INFO_LOG(resultSet != nullptr, "query resultSql is null.");
608 
609         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
610             HighlightAlbumInfo info;
611             info.highlightIdNew = std::make_optional<int32_t>(idNow++);
612             GetHighlightRowInfo(info, resultSet);
613             GetHighlightNewAlbumId(info);
614             HighlightDeduplicate(info);
615             highlightInfos_.emplace_back(info);
616         }
617         resultSet->GetRowCount(rowCount);
618         offset += PAGE_SIZE;
619         resultSet->Close();
620     } while (rowCount == PAGE_SIZE);
621     MEDIA_INFO_LOG("query tab_highlight_album nums: %{public}zu", highlightInfos_.size());
622 }
623 
GetHighlightRowInfo(HighlightAlbumInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)624 void CloneRestoreHighlight::GetHighlightRowInfo(HighlightAlbumInfo &info,
625     std::shared_ptr<NativeRdb::ResultSet> resultSet)
626 {
627     if (intersectionMap_.find("tab_highlight_album") == intersectionMap_.end()) {
628         intersectionMap_.insert(std::make_pair("tab_highlight_album", GetCommonColumns("tab_highlight_album")));
629     }
630     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_album"];
631     GetIfInIntersection("id", info.highlightIdOld, intersection, resultSet);
632     GetIfInIntersection("album_id", info.albumIdOld, intersection, resultSet);
633     GetIfInIntersection("ai_album_id", info.aiAlbumIdOld, intersection, resultSet);
634     GetIfInIntersection("sub_title", info.subTitle, intersection, resultSet);
635     GetIfInIntersection("cluster_type", info.clusterType, intersection, resultSet);
636     GetIfInIntersection("cluster_sub_type", info.clusterSubType, intersection, resultSet);
637     GetIfInIntersection("cluster_condition", info.clusterCondition, intersection, resultSet);
638     GetIfInIntersection("min_date_added", info.minDateAdded, intersection, resultSet);
639     GetIfInIntersection("max_date_added", info.maxDateAdded, intersection, resultSet);
640     GetIfInIntersection("generate_time", info.generateTime, intersection, resultSet);
641     GetIfInIntersection("highlight_version", info.highlightVersion, intersection, resultSet);
642     GetIfInIntersection("remarks", info.remarks, intersection, resultSet);
643     GetIfInIntersection("highlight_status", info.highlightStatus, intersection, resultSet);
644     GetIfInIntersection("insert_pic_count", info.insertPicCount, intersection, resultSet);
645     GetIfInIntersection("remove_pic_count", info.removePicCount, intersection, resultSet);
646     GetIfInIntersection("share_screenshot_count", info.shareScreenshotCount, intersection, resultSet);
647     GetIfInIntersection("share_cover_count", info.shareCoverCount, intersection, resultSet);
648     GetIfInIntersection("rename_count", info.renameCount, intersection, resultSet);
649     GetIfInIntersection("change_cover_count", info.changeCoverCount, intersection, resultSet);
650     GetIfInIntersection("render_viewed_times", info.renderViewedTimes, intersection, resultSet);
651     GetIfInIntersection("render_viewed_duration", info.renderViewedDuration, intersection, resultSet);
652     GetIfInIntersection("art_layout_viewed_times", info.artLayoutViewedTimes, intersection, resultSet);
653     GetIfInIntersection("art_layout_viewed_duration", info.artLayoutViewedDuration, intersection, resultSet);
654     GetIfInIntersection("music_edit_count", info.musicEditCount, intersection, resultSet);
655     GetIfInIntersection("filter_edit_count", info.filterEditCount, intersection, resultSet);
656     GetIfInIntersection("is_muted", info.isMuted, intersection, resultSet);
657     GetIfInIntersection("is_favorite", info.isFavorite, intersection, resultSet);
658     GetIfInIntersection("theme", info.theme, intersection, resultSet);
659     GetIfInIntersection("pin_time", info.pinTime, intersection, resultSet);
660     GetIfInIntersection("use_subtitle", info.useSubtitle, intersection, resultSet);
661     GetIfInIntersection("highlight_location", info.highlightLocation, intersection, resultSet);
662 }
663 
GetHighlightNewAlbumId(HighlightAlbumInfo & info)664 void CloneRestoreHighlight::GetHighlightNewAlbumId(HighlightAlbumInfo &info)
665 {
666     info.albumIdNew = info.albumIdOld;
667     info.aiAlbumIdNew = info.aiAlbumIdOld;
668 
669     if (info.albumIdOld.has_value()) {
670         auto it = std::find_if(analysisInfos_.begin(), analysisInfos_.end(),
671             [info](const AnalysisAlbumInfo &analysisInfo) {
672                 return analysisInfo.albumIdOld.has_value() &&
673                     analysisInfo.albumIdOld.value() == info.albumIdOld.value();
674             });
675         if (it != analysisInfos_.end()) {
676             info.albumIdNew = it->albumIdNew;
677             it->highlightIdOld = info.highlightIdOld;
678             it->highlightIdNew = info.highlightIdNew;
679         }
680     }
681 
682     if (info.aiAlbumIdOld.has_value()) {
683         auto it = std::find_if(analysisInfos_.begin(), analysisInfos_.end(),
684             [info](const AnalysisAlbumInfo &analysisInfo) {
685                 return analysisInfo.albumIdOld.has_value() &&
686                     analysisInfo.albumIdOld.value() == info.aiAlbumIdOld.value();
687             });
688         if (it != analysisInfos_.end()) {
689             info.aiAlbumIdNew = it->albumIdNew;
690             it->highlightIdOld = info.highlightIdOld;
691             it->highlightIdNew = info.highlightIdNew;
692         }
693     }
694 }
695 
InsertIntoHighlightAlbum()696 void CloneRestoreHighlight::InsertIntoHighlightAlbum()
697 {
698     size_t offset = 0;
699     do {
700         std::vector<NativeRdb::ValuesBucket> values;
701         for (size_t index = 0; index < PAGE_SIZE && index + offset < highlightInfos_.size(); index++) {
702             bool cond = (!highlightInfos_[index + offset].clusterType.has_value() ||
703                 !highlightInfos_[index + offset].clusterSubType.has_value() ||
704                 !highlightInfos_[index + offset].clusterCondition.has_value() ||
705                 !highlightInfos_[index + offset].highlightVersion.has_value());
706             CHECK_AND_CONTINUE(!cond);
707 
708             NativeRdb::ValuesBucket value;
709             GetHighlightInsertValue(value, highlightInfos_[index + offset]);
710             PutTempHighlightStatus(value, highlightInfos_[index + offset]);
711             values.emplace_back(value);
712         }
713         int64_t rowNum = 0;
714         int32_t errCode = BatchInsertWithRetry("tab_highlight_album", values, rowNum);
715         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
716             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
717             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
718                 "insert into tab_highlight_album fail, num:" + std::to_string(failNums));
719             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
720             highlightFailedCnt_ += failNums;
721         }
722         highlightSuccessCnt_ += rowNum;
723         offset += PAGE_SIZE;
724     } while (offset < highlightInfos_.size());
725 }
726 
GetHighlightInsertValue(NativeRdb::ValuesBucket & value,const HighlightAlbumInfo & info)727 void CloneRestoreHighlight::GetHighlightInsertValue(NativeRdb::ValuesBucket &value, const HighlightAlbumInfo &info)
728 {
729     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_album"];
730     PutIfInIntersection(value, "id", info.highlightIdNew, intersection);
731     PutIfInIntersection(value, "album_id", info.albumIdNew, intersection);
732     PutIfInIntersection(value, "ai_album_id", info.aiAlbumIdNew, intersection);
733     PutIfInIntersection(value, "sub_title", info.subTitle, intersection);
734     PutIfInIntersection(value, "min_date_added", info.minDateAdded, intersection);
735     PutIfInIntersection(value, "max_date_added", info.maxDateAdded, intersection);
736     PutIfInIntersection(value, "generate_time", info.generateTime, intersection);
737     PutIfInIntersection(value, "cluster_type", info.clusterType, intersection);
738     PutIfInIntersection(value, "cluster_sub_type", info.clusterSubType, intersection);
739     PutIfInIntersection(value, "cluster_condition", info.clusterCondition, intersection);
740     PutIfInIntersection(value, "remarks", info.remarks, intersection);
741     PutIfInIntersection(value, "highlight_version", info.highlightVersion, intersection);
742     PutIfInIntersection(value, "insert_pic_count", info.insertPicCount, intersection);
743     PutIfInIntersection(value, "remove_pic_count", info.removePicCount, intersection);
744     PutIfInIntersection(value, "share_screenshot_count", info.shareScreenshotCount, intersection);
745     PutIfInIntersection(value, "share_cover_count", info.shareCoverCount, intersection);
746     PutIfInIntersection(value, "rename_count", info.renameCount, intersection);
747     PutIfInIntersection(value, "change_cover_count", info.changeCoverCount, intersection);
748     PutIfInIntersection(value, "render_viewed_times", info.renderViewedTimes, intersection);
749     PutIfInIntersection(value, "render_viewed_duration", info.renderViewedDuration, intersection);
750     PutIfInIntersection(value, "art_layout_viewed_times", info.artLayoutViewedTimes, intersection);
751     PutIfInIntersection(value, "art_layout_viewed_duration", info.artLayoutViewedDuration, intersection);
752     PutIfInIntersection(value, "music_edit_count", info.musicEditCount, intersection);
753     PutIfInIntersection(value, "filter_edit_count", info.filterEditCount, intersection);
754     PutIfInIntersection(value, "is_muted", info.isMuted, intersection);
755     PutIfInIntersection(value, "is_favorite", info.isFavorite, intersection);
756     PutIfInIntersection(value, "theme", info.theme, intersection);
757     PutIfInIntersection(value, "pin_time", info.pinTime, intersection);
758     PutIfInIntersection(value, "use_subtitle", info.useSubtitle, intersection);
759     PutIfInIntersection(value, "highlight_location", info.highlightLocation, intersection);
760 }
761 
PutTempHighlightStatus(NativeRdb::ValuesBucket & value,const HighlightAlbumInfo & info)762 void CloneRestoreHighlight::PutTempHighlightStatus(NativeRdb::ValuesBucket &value, const HighlightAlbumInfo &info)
763 {
764     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_album"];
765     std::optional<int32_t> status = info.highlightStatus;
766     CHECK_AND_EXECUTE(info.highlightStatus.value_or(HIGHLIGHT_STATUS_NOT_PRODUCE) <= 0,
767         status = std::make_optional<int32_t>(HIGHLIGHT_STATUS_NOT_PRODUCE));
768     PutIfInIntersection(value, "highlight_status", status, intersection);
769 }
770 
MoveHighlightCovers()771 void CloneRestoreHighlight::MoveHighlightCovers()
772 {
773     std::unordered_set<int32_t> hasMovedAlbums;
774     for (const auto &info : analysisInfos_) {
775         bool cond = (!info.albumIdNew.has_value() || !info.oldCoverUri.has_value() ||
776             !info.highlightIdOld.has_value() || !info.highlightIdNew.has_value());
777         CHECK_AND_CONTINUE(!cond);
778         CHECK_AND_CONTINUE(hasMovedAlbums.count(info.highlightIdOld.value()) <= 0);
779         hasMovedAlbums.insert(info.highlightIdOld.value());
780         std::string srcDir = coverPath_ + std::to_string(info.highlightIdOld.value()) + "/";
781         MoveHighlightWordart(info, srcDir);
782         MoveHighlightGround(info, srcDir);
783     }
784 }
785 
MoveHighlightWordart(const AnalysisAlbumInfo & info,const std::string & srcDir)786 void CloneRestoreHighlight::MoveHighlightWordart(const AnalysisAlbumInfo &info, const std::string &srcDir)
787 {
788     for (const auto &ratio : HIGHLIGHT_RATIO_WORD_ART) {
789         std::string srcPath = srcDir + ratio + "/wordart.png";
790         CHECK_AND_CONTINUE(MediaFileUtils::IsFileExists(srcPath));
791         std::string dstDir = "/storage/media/local/files/highlight/cover/" +
792             std::to_string(info.highlightIdNew.value()) + "/" + ratio;
793         CHECK_AND_CONTINUE_ERR_LOG(MediaFileUtils::CreateDirectory(dstDir), "create %{public}s failed",
794             BackupFileUtils::GarbleFilePath(dstDir, sceneCode_, GARBLE_DST_PATH).c_str());
795 
796         std::string dstPath = dstDir + "/wordart.png";
797         int32_t errCode = BackupFileUtils::MoveFile(srcPath.c_str(), dstPath.c_str(), sceneCode_);
798         CHECK_AND_PRINT_LOG(errCode == E_OK, "move file failed, srcPath:%{public}s,"
799             " dstPath:%{public}s, errCode:%{public}d",
800             BackupFileUtils::GarbleFilePath(srcPath, sceneCode_, garblePath_).c_str(),
801             BackupFileUtils::GarbleFilePath(dstPath, sceneCode_, GARBLE_DST_PATH).c_str(), errCode);
802     }
803 }
804 
MoveHighlightGround(const AnalysisAlbumInfo & info,const std::string & srcDir)805 void CloneRestoreHighlight::MoveHighlightGround(const AnalysisAlbumInfo &info, const std::string &srcDir)
806 {
807     for (const auto &fileName : HIGHLIGHT_COVER_NAME) {
808         std::string groundPath = srcDir + "/full/" + fileName + ".png";
809         std::string groundDstDir = "/storage/media/local/files/highlight/cover/" +
810             std::to_string(info.highlightIdNew.value()) + "/full";
811         CHECK_AND_CONTINUE(MediaFileUtils::IsFileExists(groundPath));
812         CHECK_AND_CONTINUE_ERR_LOG(MediaFileUtils::CreateDirectory(groundDstDir), "create %{public}s failed",
813             BackupFileUtils::GarbleFilePath(groundDstDir, sceneCode_, GARBLE_DST_PATH).c_str());
814 
815         std::string groundDstPath = groundDstDir + "/" + fileName + ".png";
816         int32_t errCode = BackupFileUtils::MoveFile(groundPath.c_str(), groundDstPath.c_str(), sceneCode_);
817         CHECK_AND_PRINT_LOG(errCode == E_OK,
818             "move file failed, srcPath:%{public}s, dstPath:%{public}s, errCode:%{public}d",
819             BackupFileUtils::GarbleFilePath(groundPath, sceneCode_, garblePath_).c_str(),
820             BackupFileUtils::GarbleFilePath(groundDstPath, sceneCode_, GARBLE_DST_PATH).c_str(), errCode);
821     }
822 }
823 
MoveHighlightMusic(const std::string & srcDir,const std::string & dstDir)824 int32_t CloneRestoreHighlight::MoveHighlightMusic(const std::string &srcDir, const std::string &dstDir)
825 {
826     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CreateDirectory(dstDir), E_FAIL, "create dstDir %{public}s failed",
827         BackupFileUtils::GarbleFilePath(dstDir, sceneCode_, GARBLE_DST_PATH).c_str());
828     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::IsFileExists(srcDir), E_OK, "%{public}s doesn't exist, skip.",
829         BackupFileUtils::GarbleFilePath(srcDir, sceneCode_, garblePath_).c_str());
830     for (const auto &dirEntry : std::filesystem::directory_iterator{ srcDir }) {
831         std::string srcFilePath = dirEntry.path();
832         if (MediaFileUtils::IsDirectory(srcFilePath)) {
833             size_t index = srcFilePath.rfind("/");
834             CHECK_AND_CONTINUE(index != std::string::npos);
835             std::string subDir = srcFilePath.substr(index);
836             MoveHighlightMusic(srcFilePath, dstDir + subDir);
837         } else {
838             std::string tmpFilePath = srcFilePath;
839             std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
840             CHECK_AND_CONTINUE_INFO_LOG(!MediaFileUtils::IsFileExists(dstFilePath),
841                 "dst file already exists, srcPath:%{public}s, dstPath:%{public}s",
842                 BackupFileUtils::GarbleFilePath(srcFilePath, sceneCode_, garblePath_).c_str(),
843                 BackupFileUtils::GarbleFilePath(dstFilePath, sceneCode_, GARBLE_DST_PATH).c_str());
844             int32_t errCode = BackupFileUtils::MoveFile(srcFilePath.c_str(), dstFilePath.c_str(), sceneCode_);
845             CHECK_AND_PRINT_LOG(errCode == E_OK,
846                 "move file failed, srcPath:%{public}s, dstPath:%{public}s, errCode:%{public}d",
847                 BackupFileUtils::GarbleFilePath(srcFilePath, sceneCode_, garblePath_).c_str(),
848                 BackupFileUtils::GarbleFilePath(dstFilePath, sceneCode_, GARBLE_DST_PATH).c_str(), errCode);
849         }
850     }
851     return E_OK;
852 }
853 
GetHighlightCoverInfos()854 void CloneRestoreHighlight::GetHighlightCoverInfos()
855 {
856     int32_t rowCount = 0;
857     int32_t offset = 0;
858     do {
859         const std::string QUERY_SQL = "SELECT tab_highlight_cover_info.* FROM tab_highlight_cover_info "
860             " INNER JOIN tab_highlight_album AS h ON tab_highlight_cover_info.album_id = h.id "
861             " WHERE h.highlight_status > 0 "
862             " LIMIT " + std::to_string(offset) + ", " + std::to_string(PAGE_SIZE);
863         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
864         CHECK_AND_BREAK_INFO_LOG(resultSet != nullptr, "query resultSql is null.");
865 
866         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
867             auto albumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "album_id");
868             CHECK_AND_CONTINUE(albumId.has_value());
869             auto itAlbum = std::find_if(highlightInfos_.begin(), highlightInfos_.end(),
870                 [albumId](const HighlightAlbumInfo& hiInfo) {
871                     return hiInfo.highlightIdOld.has_value() && hiInfo.highlightIdOld == albumId;
872                 });
873             CHECK_AND_CONTINUE_ERR_LOG(itAlbum != highlightInfos_.end(), "can not find coverinfo in highlight");
874             HighlightCoverInfo info;
875             info.highlightIdNew = itAlbum->highlightIdNew;
876             GetCoverRowInfo(info, resultSet);
877             GetCoverGroundSourceInfo(info, resultSet);
878             coverInfos_.emplace_back(info);
879         }
880         resultSet->GetRowCount(rowCount);
881         offset += PAGE_SIZE;
882         resultSet->Close();
883     } while (rowCount == PAGE_SIZE);
884     MEDIA_INFO_LOG("query tab_highlight_cover_info nums: %{public}zu", coverInfos_.size());
885 }
886 
GetCoverRowInfo(HighlightCoverInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)887 void CloneRestoreHighlight::GetCoverRowInfo(HighlightCoverInfo &info,
888     std::shared_ptr<NativeRdb::ResultSet> resultSet)
889 {
890     if (intersectionMap_.find("tab_highlight_cover_info") == intersectionMap_.end()) {
891         intersectionMap_.insert(
892             std::make_pair("tab_highlight_cover_info", GetCommonColumns("tab_highlight_cover_info")));
893     }
894     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_cover_info"];
895     GetIfInIntersection("ratio", info.ratio, intersection, resultSet);
896     GetIfInIntersection("is_covered", info.isCovered, intersection, resultSet);
897     GetIfInIntersection("color", info.color, intersection, resultSet);
898     GetIfInIntersection("radius", info.radius, intersection, resultSet);
899     GetIfInIntersection("saturation", info.saturation, intersection, resultSet);
900     GetIfInIntersection("brightness", info.brightness, intersection, resultSet);
901     GetIfInIntersection("background_color_type", info.backgroundColorType, intersection, resultSet);
902     GetIfInIntersection("shadow_level", info.shadowLevel, intersection, resultSet);
903     GetIfInIntersection("title_scale_x", info.scaleX, intersection, resultSet);
904     GetIfInIntersection("title_scale_y", info.scaleY, intersection, resultSet);
905     GetIfInIntersection("title_rect_width", info.rectWidth, intersection, resultSet);
906     GetIfInIntersection("title_rect_height", info.rectHeight, intersection, resultSet);
907     GetIfInIntersection("background_scale_x", info.bgrScaleX, intersection, resultSet);
908     GetIfInIntersection("background_scale_y", info.bgrScaleY, intersection, resultSet);
909     GetIfInIntersection("background_rect_width", info.bgrRectWidth, intersection, resultSet);
910     GetIfInIntersection("background_rect_height", info.bgrRectHeight, intersection, resultSet);
911     GetIfInIntersection("layout_index", info.layoutIndex, intersection, resultSet);
912     GetIfInIntersection("cover_algo_version", info.coverAlgoVer, intersection, resultSet);
913     GetIfInIntersection("cover_service_version", info.coverServiceVer, intersection, resultSet);
914     GetIfInIntersection("status", info.status, intersection, resultSet);
915 }
916 
GetCoverGroundSourceInfo(HighlightCoverInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)917 void CloneRestoreHighlight::GetCoverGroundSourceInfo(HighlightCoverInfo &info,
918     std::shared_ptr<NativeRdb::ResultSet> resultSet)
919 {
920     bool cond = (!info.highlightIdNew.has_value() || !info.ratio.has_value());
921     CHECK_AND_RETURN(!cond);
922     std::string wordartPath = "/storage/media/local/files/highlight/cover/" +
923         std::to_string(info.highlightIdNew.value()) + "/" + info.ratio.value() + "/wordart.png";
924     CHECK_AND_EXECUTE(!MediaFileUtils::IsFileExists(wordartPath),
925         info.wordart = "file://media/highlight/cover/" + std::to_string(info.highlightIdNew.value()) +
926         "/" + info.ratio.value() + "/wordart.png?oper=highlight");
927 
928     for (const auto &fileName : HIGHLIGHT_COVER_NAME) {
929         std::string groundPath = "/storage/media/local/files/highlight/cover/" +
930             std::to_string(info.highlightIdNew.value()) + "/full/" + fileName + ".png";
931         if (BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, fileName).has_value()
932             && MediaFileUtils::IsFileExists(groundPath)) {
933             if (fileName == HIGHLIGHT_COVER_NAME[0]) {
934                 info.foreground = "file://media/highlight/cover/" +
935                     std::to_string(info.highlightIdNew.value()) + "/full/" + fileName + ".png?oper=highlight";
936             } else {
937                 info.background = "file://media/highlight/cover/" +
938                     std::to_string(info.highlightIdNew.value()) + "/full/" + fileName + ".png?oper=highlight";
939             }
940         }
941     }
942 }
943 
InsertIntoHighlightCoverInfo()944 void CloneRestoreHighlight::InsertIntoHighlightCoverInfo()
945 {
946     size_t offset = 0;
947     do {
948         std::vector<NativeRdb::ValuesBucket> values;
949         for (size_t index = 0; index < PAGE_SIZE && index + offset < coverInfos_.size(); index++) {
950             CHECK_AND_CONTINUE(coverInfos_[index + offset].highlightIdNew.has_value());
951             NativeRdb::ValuesBucket value;
952             GetCoverInsertValue(value, coverInfos_[index + offset]);
953             values.emplace_back(value);
954         }
955 
956         int64_t rowNum = 0;
957         int32_t errCode = BatchInsertWithRetry("tab_highlight_cover_info", values, rowNum);
958         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
959             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
960             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
961                 "insert into tab_highlight_cover_info fail, num:" + std::to_string(failNums));
962             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
963             coverInfoFailedCnt_ += failNums;
964         }
965         coverInfoSuccessCnt_ += rowNum;
966         offset += PAGE_SIZE;
967     } while (offset < coverInfos_.size());
968 }
969 
GetCoverInsertValue(NativeRdb::ValuesBucket & value,const HighlightCoverInfo & info)970 void CloneRestoreHighlight::GetCoverInsertValue(NativeRdb::ValuesBucket &value, const HighlightCoverInfo &info)
971 {
972     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_cover_info"];
973     PutIfInIntersection(value, "album_id", info.highlightIdNew, intersection);
974     PutIfInIntersection(value, "ratio", info.ratio, intersection);
975     PutIfInIntersection(value, "background", info.background, intersection);
976     PutIfInIntersection(value, "foreground", info.foreground, intersection);
977     PutIfInIntersection(value, "wordart", info.wordart, intersection);
978     PutIfInIntersection(value, "is_covered", info.isCovered, intersection);
979     PutIfInIntersection(value, "color", info.color, intersection);
980     PutIfInIntersection(value, "radius", info.radius, intersection);
981     PutIfInIntersection(value, "saturation", info.saturation, intersection);
982     PutIfInIntersection(value, "brightness", info.brightness, intersection);
983     PutIfInIntersection(value, "background_color_type", info.backgroundColorType, intersection);
984     PutIfInIntersection(value, "shadow_level", info.shadowLevel, intersection);
985     PutIfInIntersection(value, "title_scale_x", info.scaleX, intersection);
986     PutIfInIntersection(value, "title_scale_y", info.scaleY, intersection);
987     PutIfInIntersection(value, "title_rect_width", info.rectWidth, intersection);
988     PutIfInIntersection(value, "title_rect_height", info.rectHeight, intersection);
989     PutIfInIntersection(value, "background_scale_x", info.bgrScaleX, intersection);
990     PutIfInIntersection(value, "background_scale_y", info.bgrScaleY, intersection);
991     PutIfInIntersection(value, "background_rect_width", info.bgrRectWidth, intersection);
992     PutIfInIntersection(value, "background_rect_height", info.bgrRectHeight, intersection);
993     PutIfInIntersection(value, "layout_index", info.layoutIndex, intersection);
994     PutIfInIntersection(value, "cover_algo_version", info.coverAlgoVer, intersection);
995     PutIfInIntersection(value, "cover_service_version", info.coverServiceVer, intersection);
996     PutIfInIntersection(value, "status", info.status, intersection);
997 }
998 
GetHighlightPlayInfos()999 void CloneRestoreHighlight::GetHighlightPlayInfos()
1000 {
1001     int32_t rowCount = 0;
1002     int32_t offset = 0;
1003     do {
1004         const std::string QUERY_SQL = "SELECT tab_highlight_play_info.* FROM tab_highlight_play_info "
1005             " INNER JOIN tab_highlight_album AS h ON tab_highlight_play_info.album_id = h.id "
1006             " WHERE h.highlight_status > 0 "
1007             " LIMIT " + std::to_string(offset) + ", " + std::to_string(PAGE_SIZE);
1008         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
1009         CHECK_AND_BREAK_INFO_LOG(resultSet != nullptr, "query resultSql is null.");
1010         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1011             auto albumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "album_id");
1012             CHECK_AND_CONTINUE(albumId.has_value());
1013             auto itAlbum = std::find_if(highlightInfos_.begin(), highlightInfos_.end(),
1014                 [albumId](const HighlightAlbumInfo& hiInfo) {
1015                     return hiInfo.highlightIdOld.has_value() && hiInfo.highlightIdOld == albumId;
1016                 });
1017             CHECK_AND_CONTINUE_ERR_LOG(itAlbum != highlightInfos_.end(),
1018                 "can not find playinfo in highlight, albumId: %{public}d", albumId.value());
1019             HighlightPlayInfo info;
1020             info.highlightIdNew = itAlbum->highlightIdNew;
1021             GetPlayRowInfo(info, resultSet);
1022             playInfos_.emplace_back(info);
1023         }
1024         resultSet->GetRowCount(rowCount);
1025         offset += PAGE_SIZE;
1026         resultSet->Close();
1027     } while (rowCount == PAGE_SIZE);
1028     MEDIA_INFO_LOG("query tab_highlight_play_info nums: %{public}zu", playInfos_.size());
1029 }
1030 
GetPlayRowInfo(HighlightPlayInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)1031 void CloneRestoreHighlight::GetPlayRowInfo(HighlightPlayInfo &info,
1032     std::shared_ptr<NativeRdb::ResultSet> resultSet)
1033 {
1034     if (intersectionMap_.find("tab_highlight_play_info") == intersectionMap_.end()) {
1035         intersectionMap_.insert(
1036             std::make_pair("tab_highlight_play_info", GetCommonColumns("tab_highlight_play_info")));
1037     }
1038     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_play_info"];
1039     GetIfInIntersection("play_info_id", info.playId, intersection, resultSet);
1040     GetIfInIntersection("music", info.music, intersection, resultSet);
1041     GetIfInIntersection("filter", info.filter, intersection, resultSet);
1042     GetIfInIntersection("is_chosen", info.isChosen, intersection, resultSet);
1043     GetIfInIntersection("play_info_version", info.pInfoVer, intersection, resultSet);
1044     GetIfInIntersection("highlighting_algo_version", info.hAlgoVer, intersection, resultSet);
1045     GetIfInIntersection("camera_movement_algo_version", info.cameraAlgoVer, intersection, resultSet);
1046     GetIfInIntersection("transition_algo_version", info.transAlgoVer, intersection, resultSet);
1047     GetIfInIntersection("play_service_version", info.playServiceVer, intersection, resultSet);
1048     GetIfInIntersection("status", info.status, intersection, resultSet);
1049 }
1050 
InsertIntoHighlightPlayInfo()1051 void CloneRestoreHighlight::InsertIntoHighlightPlayInfo()
1052 {
1053     size_t offset = 0;
1054     do {
1055         std::vector<NativeRdb::ValuesBucket> values;
1056         for (size_t index = 0; index < PAGE_SIZE && index + offset < playInfos_.size(); index++) {
1057             CHECK_AND_CONTINUE(playInfos_[index + offset].highlightIdNew.has_value());
1058             NativeRdb::ValuesBucket value;
1059             GetPlayInsertValue(value, playInfos_[index + offset]);
1060             value.PutString("play_info", GetDefaultPlayInfo());
1061             values.emplace_back(value);
1062         }
1063 
1064         int64_t rowNum = 0;
1065         int32_t errCode = BatchInsertWithRetry("tab_highlight_play_info", values, rowNum);
1066         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
1067             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
1068             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
1069                 "insert into tab_highlight_play_info fail, num:" + std::to_string(failNums));
1070             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
1071             playInfoFailedCnt_ += failNums;
1072         }
1073         playInfoSuccessCnt_ += rowNum;
1074         offset += PAGE_SIZE;
1075     } while (offset < playInfos_.size());
1076 }
1077 
GetPlayInsertValue(NativeRdb::ValuesBucket & value,const HighlightPlayInfo & info)1078 void CloneRestoreHighlight::GetPlayInsertValue(NativeRdb::ValuesBucket &value, const HighlightPlayInfo &info)
1079 {
1080     std::unordered_set<std::string>& intersection = intersectionMap_["tab_highlight_play_info"];
1081     PutIfInIntersection(value, "album_id", info.highlightIdNew, intersection);
1082     PutIfInIntersection(value, "play_info_id", info.playId, intersection);
1083     PutIfInIntersection(value, "music", info.music, intersection);
1084     PutIfInIntersection(value, "filter", info.filter, intersection);
1085     PutIfInIntersection(value, "is_chosen", info.isChosen, intersection);
1086     PutIfInIntersection(value, "play_info_version", info.pInfoVer, intersection);
1087     PutIfInIntersection(value, "highlighting_algo_version", info.hAlgoVer, intersection);
1088     PutIfInIntersection(value, "camera_movement_algo_version", info.cameraAlgoVer, intersection);
1089     PutIfInIntersection(value, "transition_algo_version", info.transAlgoVer, intersection);
1090     PutIfInIntersection(value, "play_service_version", info.playServiceVer, intersection);
1091     PutIfInIntersection(value, "status", info.status, intersection);
1092 }
1093 
GetCommonColumns(const std::string & tableName)1094 std::unordered_set<std::string> CloneRestoreHighlight::GetCommonColumns(const std::string &tableName)
1095 {
1096     std::unordered_map<std::string, std::string> srcColumnInfoMap =
1097         BackupDatabaseUtils::GetColumnInfoMap(mediaRdb_, tableName);
1098     std::unordered_map<std::string, std::string> dstColumnInfoMap =
1099         BackupDatabaseUtils::GetColumnInfoMap(mediaLibraryRdb_, tableName);
1100     std::unordered_set<std::string> result;
1101     auto comparedColumns = GetValueFromMap(ALBUM_COLUMNS_MAP, tableName);
1102     for (auto it = dstColumnInfoMap.begin(); it != dstColumnInfoMap.end(); ++it) {
1103         bool cond = (srcColumnInfoMap.find(it->first) != srcColumnInfoMap.end() &&
1104             comparedColumns.count(it->first) > 0);
1105         CHECK_AND_EXECUTE(!cond, result.insert(it->first));
1106     }
1107     return result;
1108 }
1109 
ReportCloneRestoreHighlightTask()1110 void CloneRestoreHighlight::ReportCloneRestoreHighlightTask()
1111 {
1112     ReportRestoreTaskOfTotal();
1113     ReportRestoreTaskOfAlbumStats();
1114     ReportRestoreTaskOfAlbumInfo();
1115 }
1116 
ReportRestoreTaskOfTotal()1117 void CloneRestoreHighlight::ReportRestoreTaskOfTotal()
1118 {
1119     std::stringstream totalReport;
1120     totalReport << "isHighlightDirExist: " << isHighlightDirExist_ << ", timeCost: " << restoreTimeCost_ <<
1121         "; ALBUM: max_id: " << maxIdOfAlbum_ << ", success: " << albumSuccessCnt_ <<
1122         ", duplicate: " << albumDuplicateCnt_ << ", failed: " << albumFailedCnt_ <<
1123         "; HIGHLIGHT: max_id: " << maxIdOfHighlight_ << ", success: " << highlightSuccessCnt_ <<
1124         ", duplicate: " << highlightDuplicateCnt_ << ", failed: " << highlightFailedCnt_ <<
1125         "; MAP: success: " << mapSuccessCnt_ << ", failed: " << mapFailedCnt_ <<
1126         "; COVER_INFO: success: " << coverInfoSuccessCnt_ << ", failed: " << coverInfoFailedCnt_ <<
1127         "; PLAY_INFO: success: " << playInfoSuccessCnt_ << ", failed: " << playInfoFailedCnt_;
1128     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
1129         .Report("CLONE_RESTORE_HIGHLIGHT_TOTAL", RESTORE_STATUS_SUCCESS, totalReport.str());
1130 }
1131 
ReportRestoreTaskOfAlbumStats()1132 void CloneRestoreHighlight::ReportRestoreTaskOfAlbumStats()
1133 {
1134     int32_t maxCnt = 0;
1135     int32_t totalCnt = 0;
1136     for (const auto &counter : albumPhotoCounter_) {
1137         maxCnt = maxCnt > counter.second ? maxCnt : counter.second;
1138         totalCnt += counter.second;
1139     }
1140     double meanCnt = albumPhotoCounter_.size() == 0 ? 0 : (double) totalCnt / albumPhotoCounter_.size();
1141     std::stringstream albumStatsReport;
1142     albumStatsReport << "num: " << albumPhotoCounter_.size() << ", max: " << maxCnt << ", mean: " << meanCnt
1143         << ", total: " << totalCnt;
1144     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
1145         .Report("CLONE_RESTORE_HIGHLIGHT_ALBUM_STATS", RESTORE_STATUS_SUCCESS, albumStatsReport.str());
1146 }
1147 
ReportRestoreTaskOfAlbumInfo()1148 void CloneRestoreHighlight::ReportRestoreTaskOfAlbumInfo()
1149 {
1150     for (const auto &counter : albumPhotoCounter_) {
1151         std::stringstream albumInfoReport;
1152         albumInfoReport << "albumName: " << counter.first << ", photo count: " << counter.second;
1153         UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
1154             .ReportInAudit("CLONE_RESTORE_HIGHLIGHT_ALBUM_INFO", RESTORE_STATUS_SUCCESS, albumInfoReport.str());
1155     }
1156 }
1157 
HighlightDeduplicate(const HighlightAlbumInfo & info)1158 void CloneRestoreHighlight::HighlightDeduplicate(const HighlightAlbumInfo &info)
1159 {
1160     std::string duplicateAlbumName = "";
1161     std::unordered_set<int32_t> duplicateAnalysisAlbumIdSet;
1162     std::vector<NativeRdb::ValueObject> changeIds =
1163         GetHighlightDuplicateIds(info, duplicateAlbumName, duplicateAnalysisAlbumIdSet);
1164     UpdateHighlightDuplicateRows(changeIds, duplicateAlbumName);
1165     DeleteAnalysisDuplicateRows(duplicateAnalysisAlbumIdSet, duplicateAlbumName);
1166 }
1167 
GetHighlightDuplicateIds(const HighlightAlbumInfo & info,std::string & duplicateAlbumName,std::unordered_set<int32_t> & duplicateAnalysisAlbumIdSet)1168 std::vector<NativeRdb::ValueObject> CloneRestoreHighlight::GetHighlightDuplicateIds(const HighlightAlbumInfo &info,
1169     std::string &duplicateAlbumName, std::unordered_set<int32_t> &duplicateAnalysisAlbumIdSet)
1170 {
1171     std::vector<NativeRdb::ValueObject> changeIds = {};
1172     CHECK_AND_RETURN_RET((info.clusterType.has_value() && info.clusterSubType.has_value() &&
1173         info.clusterCondition.has_value() && info.highlightVersion.has_value() && info.albumIdOld.has_value()),
1174         changeIds);
1175     CHECK_AND_RETURN_RET((!info.highlightStatus.has_value() || info.highlightStatus.value() > 0), changeIds);
1176 
1177     auto it = std::find_if(analysisInfos_.begin(), analysisInfos_.end(),
1178         [info](const AnalysisAlbumInfo &analysisInfo) {
1179             return analysisInfo.albumIdOld.has_value() &&
1180                 analysisInfo.albumIdOld.value() == info.albumIdOld.value();
1181         });
1182     CHECK_AND_RETURN_RET((it != analysisInfos_.end() && it->albumName.has_value()), changeIds);
1183     duplicateAlbumName = it->albumName.value();
1184 
1185     const std::string QUERY_SQL = "SELECT t.id, t.album_id, t.ai_album_id "
1186         "FROM tab_highlight_album AS t INNER JOIN AnalysisAlbum AS a "
1187         "ON t.album_id = a.album_id WHERE t.cluster_type = ? AND t.cluster_sub_type = ? AND t.cluster_condition = ? "
1188         "AND a.album_name = ? AND t.highlight_status <> ?";
1189     std::vector<NativeRdb::ValueObject> params = {
1190         info.clusterType.value(), info.clusterSubType.value(), info.clusterCondition.value(), duplicateAlbumName,
1191         HIGHLIGHT_STATUS_DELETE
1192     };
1193     auto resultSet = BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, QUERY_SQL, params);
1194 
1195     CHECK_AND_RETURN_RET((resultSet != nullptr), changeIds);
1196 
1197     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1198         resultSet->Close();
1199         return changeIds;
1200     }
1201 
1202     do {
1203         std::optional<int32_t> highlightId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "id");
1204         std::optional<int32_t> albumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "album_id");
1205         std::optional<int32_t> aiAlbumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "ai_album_id");
1206         CHECK_AND_CONTINUE(highlightId.has_value());
1207         changeIds.emplace_back(highlightId.value());
1208         CHECK_AND_EXECUTE(!albumId.has_value(), duplicateAnalysisAlbumIdSet.insert(albumId.value()));
1209         CHECK_AND_EXECUTE(!aiAlbumId.has_value(), duplicateAnalysisAlbumIdSet.insert(aiAlbumId.value()));
1210     } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
1211     resultSet->Close();
1212     return changeIds;
1213 }
1214 
UpdateHighlightDuplicateRows(const std::vector<NativeRdb::ValueObject> & changeIds,const std::string & duplicateAlbumName)1215 void CloneRestoreHighlight::UpdateHighlightDuplicateRows(const std::vector<NativeRdb::ValueObject> &changeIds,
1216     const std::string &duplicateAlbumName)
1217 {
1218     CHECK_AND_RETURN(!changeIds.empty());
1219     int32_t changedRows = 0;
1220     std::unique_ptr<NativeRdb::AbsRdbPredicates> updatePredicates =
1221         make_unique<NativeRdb::AbsRdbPredicates>("tab_highlight_album");
1222     updatePredicates->In("id", changeIds);
1223     NativeRdb::ValuesBucket rdbValues;
1224     rdbValues.PutInt("highlight_status", HIGHLIGHT_STATUS_DELETE);
1225     BackupDatabaseUtils::Update(mediaLibraryRdb_, changedRows, rdbValues, updatePredicates);
1226     MEDIA_INFO_LOG("deduplicate highlight album, duplicate album name: %{public}s, duplicate nums: %{public}zu, "
1227         "update nums: %{public}d", duplicateAlbumName.c_str(), changeIds.size(), changedRows);
1228     highlightDuplicateCnt_ += changedRows;
1229 }
1230 
DeleteAnalysisDuplicateRows(const std::unordered_set<int32_t> & duplicateAnalysisAlbumIdSet,const std::string & duplicateAlbumName)1231 void CloneRestoreHighlight::DeleteAnalysisDuplicateRows(const std::unordered_set<int32_t> &duplicateAnalysisAlbumIdSet,
1232     const std::string &duplicateAlbumName)
1233 {
1234     CHECK_AND_RETURN(!duplicateAnalysisAlbumIdSet.empty());
1235     int32_t deleteRows = 0;
1236     std::vector<NativeRdb::ValueObject> duplicateAnalysisAlbumIds(duplicateAnalysisAlbumIdSet.begin(),
1237         duplicateAnalysisAlbumIdSet.end());
1238     NativeRdb::AbsRdbPredicates deletePredicates("AnalysisAlbum");
1239     deletePredicates.In("album_id", duplicateAnalysisAlbumIds);
1240     BackupDatabaseUtils::Delete(deletePredicates, deleteRows, mediaLibraryRdb_);
1241     MEDIA_INFO_LOG("delete duplicate analysis album, duplicate album name: %{public}s, duplicate nums: %{public}zu, "
1242         "delete nums: %{public}d", duplicateAlbumName.c_str(), duplicateAnalysisAlbumIds.size(), deleteRows);
1243     albumDuplicateCnt_ += deleteRows;
1244 }
1245 
UpdateRestoreTimeCost(int64_t timeCost)1246 void CloneRestoreHighlight::UpdateRestoreTimeCost(int64_t timeCost)
1247 {
1248     restoreTimeCost_ += timeCost;
1249 }
1250 } // namespace OHOS::Media