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 #include <libxml/parser.h>
17 #include <libxml/tree.h>
18
19 #include "highlight_restore.h"
20
21 #include "backup_database_utils.h"
22 #include "medialibrary_data_manager_utils.h"
23 #include "media_file_utils.h"
24 #include "media_log.h"
25 #include "upgrade_restore_task_report.h"
26
27 namespace OHOS::Media {
28 const int32_t PAGE_SIZE = 200;
29 const int32_t HIGHLIGHT_STATUS_SUCCESS = 1;
30 const int32_t HIGHLIGHT_STATUS_FAIL = -2;
31 const int32_t HIGHLIGHT_STATUS_DUPLICATE = -1;
32 const std::vector<std::string> HIGHLIGHT_RATIO = {
33 "1_1", "3_2", "3_4", "microcard", "medium_card", "big_card", "screen_0_ver", "screen_0_hor"
34 };
35 const std::unordered_map<std::string, std::string> CLUSTER_SUB_TYPE_MAP = {
36 { "AttractionsAlbum", "Old_Attraction" },
37 { "LocationRenamed", "Old_AOI" },
38 { "FrequencyLocationGrowingCluster", "Old_FrequencyLocation" },
39 { "RegionalFoodGrowingCluster", "Old_RegionalFood" },
40 { "CatGrowingCluster", "Old_Cat" },
41 { "DogGrowingCluster", "Old_Dog" },
42 { "PeopleGrowingCluster", "Old_People" },
43 { "LifeStageCluster", "Old_LifeStage" },
44 { "夜色", "Old_Heaven" },
45 { "恰同学少年", "Old_Graduate" },
46 { "我们毕业了", "Old_Graduate" },
47 { "DEFAULT_DBSCAN", "Old_DBSCAN" },
48 { "", "Old_Null" }
49 };
50 const std::unordered_map<std::string, std::string> CLUSTER_TYPE_MAP = { { "DBSCANTIME", "TYPE_DBSCAN" } };
51
Init(int32_t sceneCode,std::string taskId,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::shared_ptr<NativeRdb::RdbStore> galleryRdb)52 void HighlightRestore::Init(int32_t sceneCode, std::string taskId,
53 std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb, std::shared_ptr<NativeRdb::RdbStore> galleryRdb)
54 {
55 sceneCode_ = sceneCode;
56 taskId_ = taskId;
57 mediaLibraryRdb_ = mediaLibraryRdb;
58 galleryRdb_ = galleryRdb;
59 albumPhotoCounter_.clear();
60 successCnt_ = 0;
61 duplicateCnt_ = 0;
62 failCnt_ = 0;
63 tracksParseFailCnt_ = 0;
64 }
65
RestoreAlbums(const std::string & albumOdid)66 void HighlightRestore::RestoreAlbums(const std::string &albumOdid)
67 {
68 bool cond = (galleryRdb_ == nullptr || mediaLibraryRdb_ == nullptr);
69 CHECK_AND_RETURN_LOG(!cond, "rdbStore is nullptr");
70
71 GetAlbumInfos(albumOdid);
72 InsertIntoAnalysisAlbum();
73 UpdateAlbumIds();
74 InsertIntoHighlightTables();
75 }
76
GetAlbumInfos(const std::string & albumOdid)77 void HighlightRestore::GetAlbumInfos(const std::string &albumOdid)
78 {
79 const std::string QUERY_SQL = "SELECT story_id, date, name, min_datetaken, max_datetaken, "
80 "cover_id, album_type, generatedtime, cluster_type, cluster_sub_type, cluster_condition, "
81 "(SELECT COUNT(1) FROM t_story_album_suggestion "
82 "WHERE t_story_album_suggestion.story_id = t_story_album.story_id) AS suggestion "
83 "FROM t_story_album WHERE COALESCE(name, '') <> '' AND displayable = 1 LIMIT ?, ?";
84 int rowCount = 0;
85 int offset = 0;
86 do {
87 std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
88 auto resultSet = BackupDatabaseUtils::QuerySql(galleryRdb_, QUERY_SQL, params);
89 if (resultSet == nullptr) {
90 MEDIA_ERR_LOG("resultSet is nullptr");
91 break;
92 }
93 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
94 HighlightAlbumInfo info;
95 info.albumOdid = albumOdid;
96 info.albumIdOld = GetInt32Val("story_id", resultSet);
97 info.subTitle = GetStringVal("date", resultSet);
98 info.albumName = GetStringVal("name", resultSet);
99 info.minDateAdded = GetInt64Val("min_datetaken", resultSet);
100 info.maxDateAdded = GetInt64Val("max_datetaken", resultSet);
101 info.coverId = GetInt32Val("cover_id", resultSet);
102 info.generateTime = GetInt64Val("generatedtime", resultSet);
103 info.generateTime = info.generateTime != 0 ? info.generateTime : info.maxDateAdded;
104
105 info.clusterType = GetStringVal("cluster_type", resultSet);
106 info.clusterSubType = GetStringVal("cluster_sub_type", resultSet);
107 info.clusterCondition = GetStringVal("cluster_condition", resultSet);
108 TransferClusterInfo(info);
109 int32_t suggestion = GetInt32Val("suggestion", resultSet);
110 if (suggestion) {
111 info.clusterType = info.clusterType + "_suggestion";
112 }
113 int32_t albumType = GetInt32Val("album_type", resultSet);
114 info.clusterSubType = info.clusterSubType + "_" + std::to_string(albumType);
115 info.highlightStatus = !HasSameHighlightAlbum(info) ? HIGHLIGHT_STATUS_SUCCESS : HIGHLIGHT_STATUS_DUPLICATE;
116 albumInfos_.emplace_back(info);
117 }
118 resultSet->GetRowCount(rowCount);
119 resultSet->Close();
120 offset += PAGE_SIZE;
121 } while (rowCount == PAGE_SIZE);
122 }
123
HasSameHighlightAlbum(HighlightAlbumInfo & info)124 bool HighlightRestore::HasSameHighlightAlbum(HighlightAlbumInfo &info)
125 {
126 const std::string QUERY_SQL = "SELECT highlight.id, highlight.album_id, highlight.ai_album_id FROM "
127 "tab_highlight_album highlight "
128 "LEFT JOIN AnalysisAlbum album ON highlight.album_id = album.album_id "
129 "WHERE highlight.cluster_type = ? AND highlight.cluster_sub_type = ? AND highlight.cluster_condition = ? "
130 "AND album.album_name = ? AND highlight.highlight_status = 1";
131 std::vector<NativeRdb::ValueObject> params = {
132 info.clusterType, info.clusterSubType, info.clusterCondition, info.albumName
133 };
134 std::shared_ptr<NativeRdb::ResultSet> resultSet =
135 BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, QUERY_SQL, params);
136 bool cond = (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK);
137 CHECK_AND_RETURN_RET_LOG(!cond, false, "query highlight album failed.");
138
139 info.id = GetInt32Val("id", resultSet);
140 info.albumIdNew = GetInt32Val("album_id", resultSet);
141 info.aiAlbumIdNew = GetInt32Val("ai_album_id", resultSet);
142 resultSet->Close();
143 return true;
144 }
145
TransferClusterInfo(HighlightAlbumInfo & info)146 void HighlightRestore::TransferClusterInfo(HighlightAlbumInfo &info)
147 {
148 if (info.clusterType.empty()) {
149 info.clusterType = "TYPE_NULL";
150 info.clusterSubType = "Old_Null";
151 nlohmann::json jsonObjects;
152 jsonObjects.push_back({
153 { "start", std::to_string(info.minDateAdded) }, { "end", std::to_string(info.maxDateAdded) }
154 });
155 info.clusterCondition = jsonObjects.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
156 return;
157 }
158
159 info.clusterType = CLUSTER_TYPE_MAP.count(info.clusterType) > 0 ?
160 CLUSTER_TYPE_MAP.at(info.clusterType) : info.clusterType;
161 nlohmann::json jsonObjects;
162 if (info.clusterType == "TYPE_DBSCAN") {
163 if (info.clusterSubType.empty()) {
164 info.clusterSubType = info.albumName;
165 }
166 info.clusterSubType = CLUSTER_SUB_TYPE_MAP.count(info.clusterSubType) > 0 ?
167 CLUSTER_SUB_TYPE_MAP.at(info.clusterSubType) : CLUSTER_SUB_TYPE_MAP.at("DEFAULT_DBSCAN");
168 jsonObjects.push_back({
169 { "start", std::to_string(info.minDateAdded) }, { "end", std::to_string(info.maxDateAdded) }
170 });
171 } else {
172 info.clusterSubType = CLUSTER_SUB_TYPE_MAP.count(info.clusterSubType) > 0 ?
173 CLUSTER_SUB_TYPE_MAP.at(info.clusterSubType) : "Old_" + info.clusterSubType;
174 nlohmann::json jsonObject = nlohmann::json::parse(info.clusterCondition, nullptr, false);
175 if (jsonObject.is_discarded() || info.clusterCondition == "null") {
176 MEDIA_ERR_LOG("Parse clusterCondition failed, %{public}s", info.ToString().c_str());
177 jsonObjects.push_back({
178 { "start", std::to_string(info.minDateAdded) }, { "end", std::to_string(info.maxDateAdded) }
179 });
180 info.clusterCondition = jsonObjects.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
181 return;
182 }
183 if (jsonObject.contains("startDate")) {
184 jsonObject["start"] = jsonObject["startDate"];
185 jsonObject.erase("startDate");
186 }
187 if (jsonObject.contains("endDate")) {
188 jsonObject["end"] = jsonObject["endDate"];
189 jsonObject.erase("endDate");
190 }
191 jsonObjects.push_back(jsonObject);
192 }
193 info.clusterCondition = jsonObjects.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
194 }
195
InsertIntoAnalysisAlbum()196 void HighlightRestore::InsertIntoAnalysisAlbum()
197 {
198 for (HighlightAlbumInfo &info : albumInfos_) {
199 if (info.highlightStatus != HIGHLIGHT_STATUS_SUCCESS) {
200 continue;
201 }
202 vector<NativeRdb::ValuesBucket> values;
203 const int64_t ROW_NUM = 2;
204 values.emplace_back(GetAnalysisAlbumValuesBucket(info, PhotoAlbumSubType::HIGHLIGHT));
205 values.emplace_back(GetAnalysisAlbumValuesBucket(info, PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS));
206 int64_t rowNum = 0;
207 int32_t errCode = BatchInsertWithRetry("AnalysisAlbum", values, rowNum);
208 if (errCode != E_OK || rowNum != ROW_NUM) {
209 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
210 MEDIA_ERR_LOG("InsertIntoAnalysisAlbum fail, %{public}s", info.ToString().c_str());
211 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
212 info.albumName + " insert into AnalysisAlbum fail.");
213 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
214 }
215 }
216 }
217
GetAnalysisAlbumValuesBucket(const HighlightAlbumInfo & info,int32_t subType)218 NativeRdb::ValuesBucket HighlightRestore::GetAnalysisAlbumValuesBucket(const HighlightAlbumInfo &info, int32_t subType)
219 {
220 NativeRdb::ValuesBucket value;
221 value.PutInt("album_type", PhotoAlbumType::SMART);
222 value.PutInt("count", 0);
223 value.PutInt("album_subtype", subType);
224 value.PutString("album_name", info.albumName);
225 value.PutLong("date_modified", info.generateTime);
226 return value;
227 }
228
UpdateAlbumIds()229 void HighlightRestore::UpdateAlbumIds()
230 {
231 CHECK_AND_RETURN(!albumInfos_.empty());
232 const std::string QUERY_SQL =
233 "SELECT album_id, album_subtype, album_name, date_modified FROM AnalysisAlbum "
234 "WHERE album_subtype IN (4104, 4105) LIMIT ?, ?";
235 int rowCount = 0;
236 int offset = 0;
237 do {
238 std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
239 auto resultSet = BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, QUERY_SQL, params);
240 if (resultSet == nullptr) {
241 MEDIA_ERR_LOG("resultSet is nullptr");
242 break;
243 }
244 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
245 int32_t albumId = GetInt32Val("album_id", resultSet);
246 int32_t albumSubType = GetInt32Val("album_subtype", resultSet);
247 std::string albumName = GetStringVal("album_name", resultSet);
248 int64_t dateModified = GetInt64Val("date_modified", resultSet);
249 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
250 [albumName, dateModified](const HighlightAlbumInfo &info) {
251 return info.albumName == albumName && info.generateTime == dateModified;
252 });
253 if (it == albumInfos_.end()) {
254 continue;
255 }
256 if (albumSubType == PhotoAlbumSubType::HIGHLIGHT) {
257 it->albumIdNew = albumId;
258 } else {
259 it->aiAlbumIdNew = albumId;
260 }
261 }
262 resultSet->GetRowCount(rowCount);
263 resultSet->Close();
264 offset += PAGE_SIZE;
265 } while (rowCount == PAGE_SIZE);
266 }
267
InsertIntoHighlightTables()268 void HighlightRestore::InsertIntoHighlightTables()
269 {
270 InsertIntoHighlightAlbum();
271 UpdateHighlightIds();
272 InsertIntoHighlightCoverAndPlayInfo();
273 }
274
InsertIntoHighlightAlbum()275 void HighlightRestore::InsertIntoHighlightAlbum()
276 {
277 const std::string INSERT_ALBUM_SQL =
278 "INSERT INTO tab_highlight_album (album_id, ai_album_id, sub_title, min_date_added, max_date_added, "
279 "generate_time, cluster_type, cluster_sub_type, cluster_condition, highlight_status, highlight_version) "
280 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 2)";
281 for (HighlightAlbumInfo &info : albumInfos_) {
282 if (info.highlightStatus != HIGHLIGHT_STATUS_SUCCESS) {
283 continue;
284 }
285 std::vector<NativeRdb::ValueObject> albumBindArgs = {
286 info.albumIdNew, info.aiAlbumIdNew, info.subTitle, info.minDateAdded, info.maxDateAdded,
287 info.generateTime, info.clusterType, info.clusterSubType, info.clusterCondition, info.highlightStatus
288 };
289 int errCode = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, INSERT_ALBUM_SQL, albumBindArgs);
290 if (errCode != E_OK) {
291 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
292 MEDIA_ERR_LOG("InsertIntoHighlightAlbum fail, %{public}s", info.ToString().c_str());
293 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
294 info.albumName + " insert into HighlightAlbum fail.");
295 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
296 }
297 }
298 }
299
InsertIntoHighlightCoverAndPlayInfo()300 void HighlightRestore::InsertIntoHighlightCoverAndPlayInfo()
301 {
302 const std::string INSERT_PLAY_INFO_SQL =
303 "INSERT INTO tab_highlight_play_info (album_id, play_service_version, status) "
304 "VALUES (?, 0, 1)";
305 for (HighlightAlbumInfo &info : albumInfos_) {
306 if (info.highlightStatus != HIGHLIGHT_STATUS_SUCCESS) {
307 continue;
308 }
309
310 vector<NativeRdb::ValuesBucket> coverValues;
311 for (const std::string &ratio : HIGHLIGHT_RATIO) {
312 NativeRdb::ValuesBucket value;
313 value.PutInt("album_id", info.id);
314 value.PutString("ratio", ratio);
315 value.PutInt("status", 1);
316 coverValues.emplace_back(value);
317 }
318 int64_t rowNum = 0;
319 int32_t errCode = BatchInsertWithRetry("tab_highlight_cover_info", coverValues, rowNum);
320 if (errCode != E_OK || rowNum != (int64_t) HIGHLIGHT_RATIO.size()) {
321 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
322 MEDIA_ERR_LOG("InsertIntoHighlightCover fail, %{public}s", info.ToString().c_str());
323 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
324 info.albumName + " insert into HighlightCover fail.");
325 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
326 }
327
328 if (info.highlightStatus != HIGHLIGHT_STATUS_SUCCESS) {
329 continue;
330 }
331
332 std::vector<NativeRdb::ValueObject> playInfoBindArgs = { info.id };
333 errCode = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, INSERT_PLAY_INFO_SQL, playInfoBindArgs);
334 if (errCode != E_OK) {
335 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
336 MEDIA_ERR_LOG("InsertIntoHighlightPlayInfo fail, %{public}s", info.ToString().c_str());
337 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
338 info.albumName + " insert into HighlightPlayInfo fail.");
339 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
340 }
341 }
342 }
343
UpdateHighlightIds()344 void HighlightRestore::UpdateHighlightIds()
345 {
346 CHECK_AND_RETURN(!albumInfos_.empty());
347 const std::string QUERY_SQL = "SELECT album_id, id FROM tab_highlight_album LIMIT ?, ?";
348 int rowCount = 0;
349 int offset = 0;
350 do {
351 std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
352 auto resultSet = BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, QUERY_SQL, params);
353 if (resultSet == nullptr) {
354 MEDIA_ERR_LOG("resultSet is nullptr");
355 break;
356 }
357 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
358 int32_t albumId = GetInt32Val("album_id", resultSet);
359 int32_t id = GetInt32Val("id", resultSet);
360 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
361 [albumId](const HighlightAlbumInfo &info) {
362 return info.albumIdNew == albumId;
363 });
364 if (it == albumInfos_.end()) {
365 continue;
366 }
367 it->id = id;
368 }
369 resultSet->GetRowCount(rowCount);
370 resultSet->Close();
371 offset += PAGE_SIZE;
372 } while (rowCount == PAGE_SIZE);
373 }
374
RestoreMaps(std::vector<FileInfo> & fileInfos)375 void HighlightRestore::RestoreMaps(std::vector<FileInfo> &fileInfos)
376 {
377 if (albumInfos_.empty()) {
378 MEDIA_INFO_LOG("albumInfos_ is empty, no need to restore maps.");
379 return;
380 }
381 std::vector<NativeRdb::ValuesBucket> values;
382 BatchQueryPhoto(fileInfos);
383 for (const auto &fileInfo : fileInfos) {
384 UpdateMapInsertValues(values, fileInfo);
385 }
386 int64_t rowNum = 0;
387 int errCode = BatchInsertWithRetry("AnalysisPhotoMap", values, rowNum);
388 if (errCode != E_OK) {
389 MEDIA_ERR_LOG("RestoreMaps fail.");
390 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode), "RestoreMaps fail.");
391 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
392 }
393 }
394
BatchQueryPhoto(std::vector<FileInfo> & fileInfos)395 void HighlightRestore::BatchQueryPhoto(std::vector<FileInfo> &fileInfos)
396 {
397 std::stringstream querySql;
398 querySql << "SELECT file_id, data FROM Photos WHERE data IN (";
399 std::vector<NativeRdb::ValueObject> params;
400 int32_t count = 0;
401 for (const auto &fileInfo : fileInfos) {
402 if (fileInfo.fileIdNew > 0) {
403 continue;
404 }
405 querySql << (count++ > 0 ? "," : "");
406 querySql << "?";
407 params.push_back(fileInfo.cloudPath);
408 }
409 querySql << ")";
410 if (params.empty()) {
411 return;
412 }
413
414 auto resultSet = BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, querySql.str(), params);
415 CHECK_AND_RETURN_LOG(resultSet != nullptr, "resultSet is nullptr");
416 std::vector<NativeRdb::ValuesBucket> values;
417 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
418 int32_t fileId = GetInt32Val("file_id", resultSet);
419 std::string data = GetStringVal("data", resultSet);
420 auto it = std::find_if(fileInfos.begin(), fileInfos.end(),
421 [data](const FileInfo &info) {
422 return info.cloudPath == data;
423 });
424 if (it == fileInfos.end()) {
425 continue;
426 }
427 it->fileIdNew = fileId;
428 }
429 resultSet->Close();
430 }
431
UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> & values,const FileInfo & fileInfo)432 void HighlightRestore::UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> &values, const FileInfo &fileInfo)
433 {
434 CHECK_AND_RETURN(fileInfo.fileIdNew > 0);
435 int32_t fileIdOld = fileInfo.fileIdOld;
436 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
437 [fileIdOld](const HighlightAlbumInfo &info) { return info.coverId == fileIdOld; });
438 if (it != albumInfos_.end()) {
439 it->coverUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
440 std::to_string(fileInfo.fileIdNew), MediaFileUtils::GetExtraUri(fileInfo.displayName, fileInfo.cloudPath));
441 MEDIA_INFO_LOG("album %{public}s get coverUri %{public}s.", it->albumName.c_str(), it->coverUri.c_str());
442 }
443
444 bool cond = ((fileInfo.storyIds.empty() && fileInfo.portraitIds.empty()) || fileInfo.storyChosen == 0);
445 CHECK_AND_RETURN(!cond);
446 std::stringstream storyIdss(fileInfo.storyIds);
447 std::string storyId;
448 while (std::getline(storyIdss, storyId, ',')) {
449 UpdateMapInsertValuesByStoryId(values, fileInfo, storyId);
450 }
451
452 std::stringstream portraitIdss(fileInfo.portraitIds);
453 std::string portraitId;
454 while (std::getline(portraitIdss, portraitId, ',')) {
455 UpdateMapInsertValuesByStoryId(values, fileInfo, portraitId);
456 }
457 }
458
UpdateMapInsertValuesByStoryId(std::vector<NativeRdb::ValuesBucket> & values,const FileInfo & fileInfo,const std::string & storyId)459 void HighlightRestore::UpdateMapInsertValuesByStoryId(std::vector<NativeRdb::ValuesBucket> &values,
460 const FileInfo &fileInfo, const std::string &storyId)
461 {
462 if (!MediaLibraryDataManagerUtils::IsNumber(storyId)) {
463 return;
464 }
465 int32_t albumIdOld = std::atoi(storyId.c_str());
466 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
467 [albumIdOld](const HighlightAlbumInfo &info) { return info.albumIdOld == albumIdOld; });
468 bool cond = (it == albumInfos_.end() || it->albumIdNew <= 0 || it->aiAlbumIdNew <= 0);
469 CHECK_AND_RETURN_LOG(!cond, "no such album of albumIdOld: %{public}d", albumIdOld);
470
471 if (fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
472 it->effectline.push_back(GetEffectline(fileInfo));
473 }
474 std::lock_guard<mutex> lock(counterMutex_);
475 std::string albumName = std::to_string(it->id) + it->albumName;
476 if (albumPhotoCounter_.count(albumName) == 0) {
477 albumPhotoCounter_[albumName] = 0;
478 }
479 albumPhotoCounter_[albumName]++;
480 values.push_back(GetMapInsertValue(it->albumIdNew, fileInfo.fileIdNew));
481 values.push_back(GetMapInsertValue(it->aiAlbumIdNew, fileInfo.fileIdNew));
482 }
483
GetEffectline(const FileInfo & fileInfo)484 nlohmann::json HighlightRestore::GetEffectline(const FileInfo &fileInfo)
485 {
486 nlohmann::json effectline;
487 nlohmann::json fileId;
488 fileId.emplace_back(fileInfo.fileIdNew);
489 effectline["fileId"] = fileId;
490 nlohmann::json fileUri;
491 std::string effectVideoUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
492 std::to_string(fileInfo.fileIdNew), MediaFileUtils::GetExtraUri(fileInfo.displayName, fileInfo.cloudPath));
493 fileUri.emplace_back(effectVideoUri);
494 effectline["fileUri"] = fileUri;
495 nlohmann::json filedatemodified;
496 filedatemodified.emplace_back(fileInfo.dateModified);
497 effectline["filedatemodified"] = filedatemodified;
498 effectline["effectVideoTrack"] = GetEffectVideoTrack(fileInfo.hashCode);
499
500 effectline["effect"] = "TYPE_HILIGHT_CLIP";
501 effectline["effectVideoUri"] = effectVideoUri;
502 effectline["transitionId"] = "";
503 effectline["transitionVideoUri"] = "";
504 effectline["prefileId"] = nlohmann::json::array();
505 effectline["prefileUri"] = nlohmann::json::array();
506 effectline["prefiledatemodified"] = nlohmann::json::array();
507 return effectline;
508 }
509
GetEffectVideoTrack(const std::string & hashCode)510 nlohmann::json HighlightRestore::GetEffectVideoTrack(const std::string &hashCode)
511 {
512 const std::string QUERY_SQL = "SELECT tracks FROM t_video_semantic_analysis "
513 "WHERE hash = ? ORDER BY confidence_probability DESC LIMIT 1";
514 std::vector<NativeRdb::ValueObject> params = { hashCode };
515 auto resultSet = BackupDatabaseUtils::QuerySql(galleryRdb_, QUERY_SQL, params);
516 bool cond = (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK);
517 CHECK_AND_RETURN_RET(!cond, nlohmann::json::array());
518
519 std::string tracks = GetStringVal("tracks", resultSet);
520 resultSet->Close();
521 nlohmann::json effectVideoTrack = nlohmann::json::parse(tracks, nullptr, false);
522 if (effectVideoTrack.is_discarded()) {
523 MEDIA_ERR_LOG("EffectVideoTrack parse fail. tracks: %{public}s", tracks.c_str());
524 tracksParseFailCnt_++;
525 return nlohmann::json::array();
526 }
527 return effectVideoTrack;
528 }
529
GetMapInsertValue(int32_t albumId,int32_t fileId)530 NativeRdb::ValuesBucket HighlightRestore::GetMapInsertValue(int32_t albumId, int32_t fileId)
531 {
532 NativeRdb::ValuesBucket value;
533 value.PutInt("map_album", albumId);
534 value.PutInt("map_asset", fileId);
535 return value;
536 }
537
BatchInsertWithRetry(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)538 int32_t HighlightRestore::BatchInsertWithRetry(const std::string &tableName,
539 std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
540 {
541 CHECK_AND_RETURN_RET(!values.empty(), 0);
542 int32_t errCode = E_ERR;
543 TransactionOperations trans{ __func__ };
544 trans.SetBackupRdbStore(mediaLibraryRdb_);
545 std::function<int(void)> func = [&]() -> int {
546 errCode = trans.BatchInsert(rowNum, tableName, values);
547 CHECK_AND_PRINT_LOG(errCode == E_OK,
548 "InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.", errCode, (long)rowNum);
549 return errCode;
550 };
551 errCode = trans.RetryTrans(func, true);
552 CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: trans finish fail!, ret:%{public}d", errCode);
553 return errCode;
554 }
555
UpdateAlbums()556 void HighlightRestore::UpdateAlbums()
557 {
558 const std::string UPDATE_ALBUM_SQL = "UPDATE AnalysisAlbum SET "
559 "cover_uri = ?, "
560 "count = (SELECT count(1) FROM AnalysisPhotoMap AS apm WHERE apm.map_album = AnalysisAlbum.album_id) "
561 "WHERE album_id IN (?, ?)";
562 const std::string UPDATE_COVER_KEY_SQL = "UPDATE tab_highlight_cover_info SET "
563 "cover_key = ?||'_'||ratio||'_'||? "
564 "WHERE album_id = ?";
565 const std::string UPDATE_PLAY_INFO_SQL = "UPDATE tab_highlight_play_info SET "
566 "play_info = ? "
567 "WHERE album_id = ?";
568 const std::string DELETE_ALBUM_SQL = "DELETE FROM AnalysisAlbum WHERE album_id IN (?, ?)";
569 const std::string DELETE_HIGHLIGHT_ALBUM_SQL = "DELETE FROM tab_highlight_album WHERE id = ?";
570 const std::string DELETE_HIGHLIGHT_COVER_SQL = "DELETE FROM tab_highlight_cover_info WHERE album_id = ?";
571 const std::string DELETE_HIGHLIGHT_PLAY_INFO_SQL = "DELETE FROM tab_highlight_play_info WHERE album_id = ?";
572
573 for (const auto &info : albumInfos_) {
574 MEDIA_INFO_LOG("UpdateAlbums %{public}s", info.ToString().c_str());
575 if (info.highlightStatus != HIGHLIGHT_STATUS_FAIL) {
576 info.highlightStatus == HIGHLIGHT_STATUS_SUCCESS ? successCnt_++ : duplicateCnt_++;
577 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_ALBUM_SQL,
578 { info.coverUri, info.albumIdNew, info.aiAlbumIdNew });
579 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_COVER_KEY_SQL,
580 { info.albumName, info.coverUri, info.id });
581 nlohmann::json playInfo;
582 nlohmann::json effectline;
583 nlohmann::json effectlineArray = nlohmann::json::array();
584 for (const auto &e : info.effectline) {
585 effectlineArray.emplace_back(e);
586 }
587 effectline["effectline"] = effectlineArray;
588 playInfo["effectline"] = effectline;
589 playInfo["beatsInfo"] = nlohmann::json::array();
590 playInfo["timeline"] = nlohmann::json::array();
591 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_PLAY_INFO_SQL,
592 { playInfo.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace), info.id });
593 } else {
594 failCnt_++;
595 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_ALBUM_SQL, { info.albumIdNew, info.aiAlbumIdNew });
596 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_HIGHLIGHT_ALBUM_SQL, { info.id });
597 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_HIGHLIGHT_COVER_SQL, { info.id });
598 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_HIGHLIGHT_PLAY_INFO_SQL, { info.id });
599 }
600 }
601
602 ReportHighlightRestoreTask();
603 }
604
ReportHighlightRestoreTask()605 void HighlightRestore::ReportHighlightRestoreTask()
606 {
607 int maxCnt = 0;
608 int totalCnt = 0;
609 for (auto &counter : albumPhotoCounter_) {
610 maxCnt = maxCnt > counter.second ? maxCnt : counter.second;
611 totalCnt += counter.second;
612 MEDIA_INFO_LOG("UpdateMapInsertValues albumName: %{public}s, photo count: %{public}d",
613 counter.first.c_str(), counter.second);
614 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
615 .Report("Highlight Photo Map", std::to_string(HIGHLIGHT_STATUS_SUCCESS),
616 "albumName: " + counter.first + ", photo count: " + std::to_string(counter.second));
617 }
618 double meanCnt = albumPhotoCounter_.size() == 0 ? 0 : (double) totalCnt / albumPhotoCounter_.size();
619 MEDIA_INFO_LOG("Highlight photos max: %{public}d, mean: %{public}f", maxCnt, meanCnt);
620 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
621 .Report("Highlight Photos", std::to_string(HIGHLIGHT_STATUS_SUCCESS),
622 "max: " + std::to_string(maxCnt) + ", mean: " + std::to_string(meanCnt));
623
624 MEDIA_INFO_LOG("Highlight Restore successCnt_: %{public}d, duplicateCnt_: %{public}d, failCnt_: %{public}d",
625 successCnt_.load(), duplicateCnt_.load(), failCnt_.load());
626 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
627 .Report("Highlight Restore", std::to_string(HIGHLIGHT_STATUS_SUCCESS),
628 "successCnt_: " + std::to_string(successCnt_) + ", duplicateCnt_: " + std::to_string(duplicateCnt_) +
629 ", failCnt_: " + std::to_string(failCnt_));
630 MEDIA_ERR_LOG("EffectVideoTrack parse fail. totalCnt: %{public}d", tracksParseFailCnt_.load());
631 ErrorInfo errorInfo(RestoreError::PARSE_TRACK_FAILED, 0, "",
632 "EffectVideoTrack parse fail. totalCnt: " + std::to_string(tracksParseFailCnt_));
633 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
634 }
635 } // namespace OHOS::Media