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