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