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
RestoreHighlight(const std::string & albumOdid,const std::unordered_map<int32_t,PhotoInfo> & photoInfoMap)66 void HighlightRestore::RestoreHighlight(const std::string &albumOdid,
67 const std::unordered_map<int32_t, PhotoInfo> &photoInfoMap)
68 {
69 CHECK_AND_RETURN_LOG(galleryRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr");
70 RestoreAlbums(albumOdid);
71 RestoreMaps(photoInfoMap);
72 UpdateAlbums();
73 }
74
RestoreAlbums(const std::string & albumOdid)75 void HighlightRestore::RestoreAlbums(const std::string &albumOdid)
76 {
77 GetAlbumInfos(albumOdid);
78 InsertIntoAnalysisAlbum();
79 UpdateAlbumIds();
80 InsertIntoHighlightTables();
81 }
82
GetAlbumInfos(const std::string & albumOdid)83 void HighlightRestore::GetAlbumInfos(const std::string &albumOdid)
84 {
85 const std::string QUERY_SQL = "SELECT story_id, date, name, min_datetaken, max_datetaken, "
86 "cover_id, album_type, generatedtime, cluster_type, cluster_sub_type, cluster_condition, "
87 "(SELECT COUNT(1) FROM t_story_album_suggestion "
88 "WHERE t_story_album_suggestion.story_id = t_story_album.story_id) AS suggestion "
89 "FROM t_story_album WHERE COALESCE(name, '') <> '' AND displayable = 1 LIMIT ?, ?";
90 int rowCount = 0;
91 int offset = 0;
92 do {
93 std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
94 auto resultSet = BackupDatabaseUtils::QuerySql(galleryRdb_, QUERY_SQL, params);
95 CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
96
97 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
98 HighlightAlbumInfo info;
99 info.albumOdid = albumOdid;
100 info.albumIdOld = GetInt32Val("story_id", resultSet);
101 info.subTitle = GetStringVal("date", resultSet);
102 info.albumName = GetStringVal("name", resultSet);
103 info.minDateAdded = GetInt64Val("min_datetaken", resultSet);
104 info.maxDateAdded = GetInt64Val("max_datetaken", resultSet);
105 info.coverId = GetInt32Val("cover_id", resultSet);
106 info.generateTime = GetInt64Val("generatedtime", resultSet);
107 info.generateTime = info.generateTime != 0 ? info.generateTime : info.maxDateAdded;
108
109 info.clusterType = GetStringVal("cluster_type", resultSet);
110 info.clusterSubType = GetStringVal("cluster_sub_type", resultSet);
111 info.clusterCondition = GetStringVal("cluster_condition", resultSet);
112 TransferClusterInfo(info);
113 int32_t suggestion = GetInt32Val("suggestion", resultSet);
114 if (suggestion) {
115 info.clusterType = info.clusterType + "_suggestion";
116 }
117 int32_t albumType = GetInt32Val("album_type", resultSet);
118 info.clusterSubType = info.clusterSubType + "_" + std::to_string(albumType);
119 info.highlightStatus = !HasSameHighlightAlbum(info) ? HIGHLIGHT_STATUS_SUCCESS : HIGHLIGHT_STATUS_DUPLICATE;
120 albumInfos_.emplace_back(info);
121 }
122 resultSet->GetRowCount(rowCount);
123 resultSet->Close();
124 offset += PAGE_SIZE;
125 } while (rowCount == PAGE_SIZE);
126 }
127
HasSameHighlightAlbum(HighlightAlbumInfo & info)128 bool HighlightRestore::HasSameHighlightAlbum(HighlightAlbumInfo &info)
129 {
130 const std::string QUERY_SQL = "SELECT highlight.id, highlight.album_id, highlight.ai_album_id FROM "
131 "tab_highlight_album highlight "
132 "LEFT JOIN AnalysisAlbum album ON highlight.album_id = album.album_id "
133 "WHERE highlight.cluster_type = ? AND highlight.cluster_sub_type = ? AND highlight.cluster_condition = ? "
134 "AND album.album_name = ? AND highlight.highlight_status = 1";
135 std::vector<NativeRdb::ValueObject> params = {
136 info.clusterType, info.clusterSubType, info.clusterCondition, info.albumName
137 };
138 std::shared_ptr<NativeRdb::ResultSet> resultSet =
139 BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, QUERY_SQL, params);
140 bool cond = (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK);
141 CHECK_AND_RETURN_RET_LOG(!cond, false, "query highlight album failed.");
142
143 info.id = GetInt32Val("id", resultSet);
144 info.albumIdNew = GetInt32Val("album_id", resultSet);
145 info.aiAlbumIdNew = GetInt32Val("ai_album_id", resultSet);
146 resultSet->Close();
147 return true;
148 }
149
TransferClusterInfo(HighlightAlbumInfo & info)150 void HighlightRestore::TransferClusterInfo(HighlightAlbumInfo &info)
151 {
152 if (info.clusterType.empty()) {
153 info.clusterType = "TYPE_NULL";
154 info.clusterSubType = "Old_Null";
155 nlohmann::json jsonObjects;
156 jsonObjects.push_back({
157 { "start", std::to_string(info.minDateAdded) }, { "end", std::to_string(info.maxDateAdded) }
158 });
159 info.clusterCondition = jsonObjects.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
160 return;
161 }
162
163 info.clusterType = CLUSTER_TYPE_MAP.count(info.clusterType) > 0 ?
164 CLUSTER_TYPE_MAP.at(info.clusterType) : info.clusterType;
165 nlohmann::json jsonObjects;
166 if (info.clusterType == "TYPE_DBSCAN") {
167 CHECK_AND_EXECUTE(!info.clusterSubType.empty(), info.clusterSubType = info.albumName);
168 info.clusterSubType = CLUSTER_SUB_TYPE_MAP.count(info.clusterSubType) > 0 ?
169 CLUSTER_SUB_TYPE_MAP.at(info.clusterSubType) : CLUSTER_SUB_TYPE_MAP.at("DEFAULT_DBSCAN");
170 jsonObjects.push_back({
171 { "start", std::to_string(info.minDateAdded) }, { "end", std::to_string(info.maxDateAdded) }
172 });
173 } else {
174 info.clusterSubType = CLUSTER_SUB_TYPE_MAP.count(info.clusterSubType) > 0 ?
175 CLUSTER_SUB_TYPE_MAP.at(info.clusterSubType) : "Old_" + info.clusterSubType;
176 nlohmann::json jsonObject = nlohmann::json::parse(info.clusterCondition, nullptr, false);
177 if (jsonObject.is_discarded() || info.clusterCondition == "null") {
178 MEDIA_ERR_LOG("Parse clusterCondition failed, %{public}s", info.ToString().c_str());
179 jsonObjects.push_back({
180 { "start", std::to_string(info.minDateAdded) }, { "end", std::to_string(info.maxDateAdded) }
181 });
182 info.clusterCondition = jsonObjects.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
183 return;
184 }
185 if (jsonObject.contains("startDate")) {
186 jsonObject["start"] = jsonObject["startDate"];
187 jsonObject.erase("startDate");
188 }
189 if (jsonObject.contains("endDate")) {
190 jsonObject["end"] = jsonObject["endDate"];
191 jsonObject.erase("endDate");
192 }
193 jsonObjects.push_back(jsonObject);
194 }
195 info.clusterCondition = jsonObjects.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
196 }
197
InsertIntoAnalysisAlbum()198 void HighlightRestore::InsertIntoAnalysisAlbum()
199 {
200 for (HighlightAlbumInfo &info : albumInfos_) {
201 CHECK_AND_CONTINUE(info.highlightStatus == HIGHLIGHT_STATUS_SUCCESS);
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 CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
241 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
242 int32_t albumId = GetInt32Val("album_id", resultSet);
243 int32_t albumSubType = GetInt32Val("album_subtype", resultSet);
244 std::string albumName = GetStringVal("album_name", resultSet);
245 int64_t dateModified = GetInt64Val("date_modified", resultSet);
246 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
247 [albumName, dateModified](const HighlightAlbumInfo &info) {
248 return info.albumName == albumName && info.generateTime == dateModified;
249 });
250 CHECK_AND_CONTINUE(it != albumInfos_.end());
251 if (albumSubType == PhotoAlbumSubType::HIGHLIGHT) {
252 it->albumIdNew = albumId;
253 } else {
254 it->aiAlbumIdNew = albumId;
255 }
256 }
257 resultSet->GetRowCount(rowCount);
258 resultSet->Close();
259 offset += PAGE_SIZE;
260 } while (rowCount == PAGE_SIZE);
261 }
262
InsertIntoHighlightTables()263 void HighlightRestore::InsertIntoHighlightTables()
264 {
265 InsertIntoHighlightAlbum();
266 UpdateHighlightIds();
267 InsertIntoHighlightCoverAndPlayInfo();
268 }
269
InsertIntoHighlightAlbum()270 void HighlightRestore::InsertIntoHighlightAlbum()
271 {
272 const std::string INSERT_ALBUM_SQL =
273 "INSERT INTO tab_highlight_album (album_id, ai_album_id, sub_title, min_date_added, max_date_added, "
274 "generate_time, cluster_type, cluster_sub_type, cluster_condition, highlight_status, highlight_version) "
275 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 2)";
276 for (HighlightAlbumInfo &info : albumInfos_) {
277 CHECK_AND_CONTINUE(info.highlightStatus == HIGHLIGHT_STATUS_SUCCESS);
278 std::vector<NativeRdb::ValueObject> albumBindArgs = {
279 info.albumIdNew, info.aiAlbumIdNew, info.subTitle, info.minDateAdded, info.maxDateAdded,
280 info.generateTime, info.clusterType, info.clusterSubType, info.clusterCondition, info.highlightStatus
281 };
282 int errCode = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, INSERT_ALBUM_SQL, albumBindArgs);
283 if (errCode != E_OK) {
284 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
285 MEDIA_ERR_LOG("InsertIntoHighlightAlbum fail, %{public}s", info.ToString().c_str());
286 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
287 info.albumName + " insert into HighlightAlbum fail.");
288 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
289 }
290 }
291 }
292
InsertIntoHighlightCoverAndPlayInfo()293 void HighlightRestore::InsertIntoHighlightCoverAndPlayInfo()
294 {
295 const std::string INSERT_PLAY_INFO_SQL =
296 "INSERT INTO tab_highlight_play_info (album_id, play_service_version, status) "
297 "VALUES (?, 0, 1)";
298 for (HighlightAlbumInfo &info : albumInfos_) {
299 CHECK_AND_CONTINUE(info.highlightStatus == HIGHLIGHT_STATUS_SUCCESS);
300 vector<NativeRdb::ValuesBucket> coverValues;
301 for (const std::string &ratio : HIGHLIGHT_RATIO) {
302 NativeRdb::ValuesBucket value;
303 value.PutInt("album_id", info.id);
304 value.PutString("ratio", ratio);
305 value.PutInt("status", 1);
306 coverValues.emplace_back(value);
307 }
308
309 int64_t rowNum = 0;
310 int32_t errCode = BatchInsertWithRetry("tab_highlight_cover_info", coverValues, rowNum);
311 if (errCode != E_OK || rowNum != (int64_t) HIGHLIGHT_RATIO.size()) {
312 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
313 MEDIA_ERR_LOG("InsertIntoHighlightCover fail, %{public}s", info.ToString().c_str());
314 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
315 info.albumName + " insert into HighlightCover fail.");
316 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
317 }
318
319 CHECK_AND_CONTINUE(info.highlightStatus == HIGHLIGHT_STATUS_SUCCESS);
320 std::vector<NativeRdb::ValueObject> playInfoBindArgs = { info.id };
321 errCode = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, INSERT_PLAY_INFO_SQL, playInfoBindArgs);
322 if (errCode != E_OK) {
323 info.highlightStatus = HIGHLIGHT_STATUS_FAIL;
324 MEDIA_ERR_LOG("InsertIntoHighlightPlayInfo fail, %{public}s", info.ToString().c_str());
325 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
326 info.albumName + " insert into HighlightPlayInfo fail.");
327 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
328 }
329 }
330 }
331
UpdateHighlightIds()332 void HighlightRestore::UpdateHighlightIds()
333 {
334 CHECK_AND_RETURN(!albumInfos_.empty());
335 const std::string QUERY_SQL = "SELECT album_id, id FROM tab_highlight_album LIMIT ?, ?";
336 int rowCount = 0;
337 int offset = 0;
338 do {
339 std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
340 auto resultSet = BackupDatabaseUtils::QuerySql(mediaLibraryRdb_, QUERY_SQL, params);
341 CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
342 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
343 int32_t albumId = GetInt32Val("album_id", resultSet);
344 int32_t id = GetInt32Val("id", resultSet);
345 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
346 [albumId](const HighlightAlbumInfo &info) {
347 return info.albumIdNew == albumId;
348 });
349 CHECK_AND_CONTINUE(it != albumInfos_.end());
350 it->id = id;
351 }
352 resultSet->GetRowCount(rowCount);
353 resultSet->Close();
354 offset += PAGE_SIZE;
355 } while (rowCount == PAGE_SIZE);
356 }
357
RestoreMaps(const std::unordered_map<int32_t,PhotoInfo> & photoInfoMap)358 void HighlightRestore::RestoreMaps(const std::unordered_map<int32_t, PhotoInfo> &photoInfoMap)
359 {
360 CHECK_AND_RETURN_LOG(galleryRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr");
361 CHECK_AND_RETURN_INFO_LOG(!albumInfos_.empty(), "albumInfos_ is empty, no need to restore maps.");
362 std::string querySql = "SELECT _id, story_id, portrait_id, date_modified, hash FROM gallery_media "
363 "WHERE ((story_id IS NOT NULL AND story_id != '') OR (portrait_id IS NOT NULL AND portrait_id != '')) "
364 "AND story_chosen != 0 AND _id > ? ORDER BY _id ASC LIMIT ?;";
365 int rowCount = 0;
366 int offset = 0;
367 do {
368 std::vector<NativeRdb::ValuesBucket> values;
369 std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
370 auto resultSet = BackupDatabaseUtils::QuerySql(galleryRdb_, querySql, params);
371 CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "resultSet is nullptr");
372 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
373 HighlightPhotoInfo highlightPhoto;
374 highlightPhoto.fileIdOld = GetInt32Val("_id", resultSet);
375 offset = highlightPhoto.fileIdOld;
376 CHECK_AND_CONTINUE(photoInfoMap.find(highlightPhoto.fileIdOld) != photoInfoMap.end());
377 highlightPhoto.photoInfo = photoInfoMap.at(highlightPhoto.fileIdOld);
378 highlightPhoto.storyIds = GetStringVal("story_id", resultSet);
379 highlightPhoto.portraitIds = GetStringVal("portrait_id", resultSet);
380 highlightPhoto.hashCode = GetStringVal("hash", resultSet);
381 highlightPhoto.dateModified = GetInt64Val("date_modified", resultSet);
382 UpdateMapInsertValues(values, highlightPhoto);
383 }
384 resultSet->GetRowCount(rowCount);
385 resultSet->Close();
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 } while (rowCount == PAGE_SIZE);
394 }
395
UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> & values,const HighlightPhotoInfo & highlightPhoto)396 void HighlightRestore::UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> &values,
397 const HighlightPhotoInfo &highlightPhoto)
398 {
399 CHECK_AND_RETURN(highlightPhoto.photoInfo.fileIdNew > 0);
400 UpdateAlbumInfoCoverUris(highlightPhoto);
401
402 std::stringstream storyIdss(highlightPhoto.storyIds);
403 std::string storyId;
404 while (std::getline(storyIdss, storyId, ',')) {
405 UpdateMapInsertValuesByStoryId(values, highlightPhoto, storyId);
406 }
407
408 std::stringstream portraitIdss(highlightPhoto.portraitIds);
409 std::string portraitId;
410 while (std::getline(portraitIdss, portraitId, ',')) {
411 UpdateMapInsertValuesByStoryId(values, highlightPhoto, portraitId);
412 }
413 }
414
UpdateAlbumInfoCoverUris(const HighlightPhotoInfo & highlightPhoto)415 void HighlightRestore::UpdateAlbumInfoCoverUris(const HighlightPhotoInfo &highlightPhoto)
416 {
417 for (auto &info : albumInfos_) {
418 if (info.coverId != highlightPhoto.fileIdOld) {
419 continue;
420 }
421 info.coverUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
422 std::to_string(highlightPhoto.photoInfo.fileIdNew),
423 MediaFileUtils::GetExtraUri(highlightPhoto.photoInfo.displayName, highlightPhoto.photoInfo.cloudPath));
424 MEDIA_INFO_LOG("album %{public}s get coverUri %{public}s.", info.albumName.c_str(), info.coverUri.c_str());
425 }
426 }
427
UpdateMapInsertValuesByStoryId(std::vector<NativeRdb::ValuesBucket> & values,const HighlightPhotoInfo & highlightPhoto,const std::string & storyId)428 void HighlightRestore::UpdateMapInsertValuesByStoryId(std::vector<NativeRdb::ValuesBucket> &values,
429 const HighlightPhotoInfo &highlightPhoto, const std::string &storyId)
430 {
431 CHECK_AND_RETURN(!storyId.empty() && MediaLibraryDataManagerUtils::IsNumber(storyId));
432 int32_t albumIdOld = std::atoi(storyId.c_str());
433 auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
434 [albumIdOld](const HighlightAlbumInfo &info) { return info.albumIdOld == albumIdOld; });
435 bool cond = (it == albumInfos_.end() || it->albumIdNew <= 0 || it->aiAlbumIdNew <= 0);
436 CHECK_AND_RETURN_LOG(!cond, "no such album of albumIdOld: %{public}d", albumIdOld);
437 CHECK_AND_EXECUTE(highlightPhoto.photoInfo.fileType != MediaType::MEDIA_TYPE_VIDEO,
438 it->effectline.push_back(GetEffectline(highlightPhoto)));
439
440 std::lock_guard<mutex> lock(counterMutex_);
441 std::string albumName = std::to_string(it->id) + it->albumName;
442 CHECK_AND_EXECUTE(albumPhotoCounter_.count(albumName) != 0, albumPhotoCounter_[albumName] = 0);
443 albumPhotoCounter_[albumName]++;
444 values.push_back(GetMapInsertValue(it->albumIdNew, highlightPhoto.photoInfo.fileIdNew));
445 values.push_back(GetMapInsertValue(it->aiAlbumIdNew, highlightPhoto.photoInfo.fileIdNew));
446 }
447
GetEffectline(const HighlightPhotoInfo & highlightPhoto)448 nlohmann::json HighlightRestore::GetEffectline(const HighlightPhotoInfo &highlightPhoto)
449 {
450 nlohmann::json effectline;
451 nlohmann::json fileId;
452 fileId.emplace_back(highlightPhoto.photoInfo.fileIdNew);
453 effectline["fileId"] = fileId;
454 nlohmann::json fileUri;
455 std::string effectVideoUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
456 std::to_string(highlightPhoto.photoInfo.fileIdNew),
457 MediaFileUtils::GetExtraUri(highlightPhoto.photoInfo.displayName, highlightPhoto.photoInfo.cloudPath));
458 fileUri.emplace_back(effectVideoUri);
459 effectline["fileUri"] = fileUri;
460 nlohmann::json filedatemodified;
461 filedatemodified.emplace_back(highlightPhoto.dateModified);
462 effectline["filedatemodified"] = filedatemodified;
463 effectline["effectVideoTrack"] = GetEffectVideoTrack(highlightPhoto.hashCode);
464
465 effectline["effect"] = "TYPE_HILIGHT_CLIP";
466 effectline["effectVideoUri"] = effectVideoUri;
467 effectline["transitionId"] = "";
468 effectline["transitionVideoUri"] = "";
469 effectline["prefileId"] = nlohmann::json::array();
470 effectline["prefileUri"] = nlohmann::json::array();
471 effectline["prefiledatemodified"] = nlohmann::json::array();
472 return effectline;
473 }
474
GetEffectVideoTrack(const std::string & hashCode)475 nlohmann::json HighlightRestore::GetEffectVideoTrack(const std::string &hashCode)
476 {
477 const std::string QUERY_SQL = "SELECT tracks FROM t_video_semantic_analysis "
478 "WHERE hash = ? ORDER BY confidence_probability DESC LIMIT 1";
479 std::vector<NativeRdb::ValueObject> params = { hashCode };
480 auto resultSet = BackupDatabaseUtils::QuerySql(galleryRdb_, QUERY_SQL, params);
481 CHECK_AND_RETURN_RET(resultSet != nullptr, nlohmann::json::array());
482
483 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
484 resultSet->Close();
485 return nlohmann::json::array();
486 }
487
488 std::string tracks = GetStringVal("tracks", resultSet);
489 resultSet->Close();
490 nlohmann::json effectVideoTrack = nlohmann::json::parse(tracks, nullptr, false);
491 if (effectVideoTrack.is_discarded()) {
492 MEDIA_ERR_LOG("EffectVideoTrack parse fail. tracks: %{public}s", tracks.c_str());
493 tracksParseFailCnt_++;
494 return nlohmann::json::array();
495 }
496 return effectVideoTrack;
497 }
498
GetMapInsertValue(int32_t albumId,int32_t fileId)499 NativeRdb::ValuesBucket HighlightRestore::GetMapInsertValue(int32_t albumId, int32_t fileId)
500 {
501 NativeRdb::ValuesBucket value;
502 value.PutInt("map_album", albumId);
503 value.PutInt("map_asset", fileId);
504 return value;
505 }
506
BatchInsertWithRetry(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)507 int32_t HighlightRestore::BatchInsertWithRetry(const std::string &tableName,
508 std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
509 {
510 CHECK_AND_RETURN_RET(!values.empty(), 0);
511 int32_t errCode = E_ERR;
512 TransactionOperations trans{ __func__ };
513 trans.SetBackupRdbStore(mediaLibraryRdb_);
514 std::function<int(void)> func = [&]() -> int {
515 errCode = trans.BatchInsert(rowNum, tableName, values);
516 CHECK_AND_PRINT_LOG(errCode == E_OK,
517 "InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.", errCode, (long)rowNum);
518 return errCode;
519 };
520 errCode = trans.RetryTrans(func, true);
521 CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: trans finish fail!, ret:%{public}d", errCode);
522 return errCode;
523 }
524
UpdateAlbums()525 void HighlightRestore::UpdateAlbums()
526 {
527 CHECK_AND_RETURN_LOG(galleryRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr");
528 const std::string UPDATE_ALBUM_SQL = "UPDATE AnalysisAlbum SET "
529 "cover_uri = ?, "
530 "count = (SELECT count(1) FROM AnalysisPhotoMap AS apm WHERE apm.map_album = AnalysisAlbum.album_id) "
531 "WHERE album_id IN (?, ?)";
532 const std::string UPDATE_COVER_KEY_SQL = "UPDATE tab_highlight_cover_info SET "
533 "cover_key = ?||'_'||ratio||'_'||? "
534 "WHERE album_id = ?";
535 const std::string UPDATE_PLAY_INFO_SQL = "UPDATE tab_highlight_play_info SET "
536 "play_info = ? "
537 "WHERE album_id = ?";
538 const std::string DELETE_ALBUM_SQL = "DELETE FROM AnalysisAlbum WHERE album_id IN (?, ?)";
539 const std::string DELETE_HIGHLIGHT_ALBUM_SQL = "DELETE FROM tab_highlight_album WHERE id = ?";
540 const std::string DELETE_HIGHLIGHT_COVER_SQL = "DELETE FROM tab_highlight_cover_info WHERE album_id = ?";
541 const std::string DELETE_HIGHLIGHT_PLAY_INFO_SQL = "DELETE FROM tab_highlight_play_info WHERE album_id = ?";
542
543 for (const auto &info : albumInfos_) {
544 MEDIA_INFO_LOG("UpdateAlbums %{public}s", info.ToString().c_str());
545 if (info.highlightStatus != HIGHLIGHT_STATUS_FAIL) {
546 info.highlightStatus == HIGHLIGHT_STATUS_SUCCESS ? successCnt_++ : duplicateCnt_++;
547 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_ALBUM_SQL,
548 { info.coverUri, info.albumIdNew, info.aiAlbumIdNew });
549 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_COVER_KEY_SQL,
550 { info.albumName, info.coverUri, info.id });
551 nlohmann::json playInfo;
552 nlohmann::json effectline;
553 nlohmann::json effectlineArray = nlohmann::json::array();
554 for (const auto &e : info.effectline) {
555 effectlineArray.emplace_back(e);
556 }
557 effectline["effectline"] = effectlineArray;
558 playInfo["effectline"] = effectline;
559 playInfo["beatsInfo"] = nlohmann::json::array();
560 playInfo["timeline"] = nlohmann::json::array();
561 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, UPDATE_PLAY_INFO_SQL,
562 { playInfo.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace), info.id });
563 } else {
564 failCnt_++;
565 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_ALBUM_SQL, { info.albumIdNew, info.aiAlbumIdNew });
566 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_HIGHLIGHT_ALBUM_SQL, { info.id });
567 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_HIGHLIGHT_COVER_SQL, { info.id });
568 BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, DELETE_HIGHLIGHT_PLAY_INFO_SQL, { info.id });
569 }
570 }
571
572 ReportHighlightRestoreTask();
573 }
574
ReportHighlightRestoreTask()575 void HighlightRestore::ReportHighlightRestoreTask()
576 {
577 int maxCnt = 0;
578 int totalCnt = 0;
579 for (auto &counter : albumPhotoCounter_) {
580 maxCnt = maxCnt > counter.second ? maxCnt : counter.second;
581 totalCnt += counter.second;
582 MEDIA_INFO_LOG("UpdateMapInsertValues albumName: %{public}s, photo count: %{public}d",
583 counter.first.c_str(), counter.second);
584 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
585 .Report("Highlight Photo Map", std::to_string(HIGHLIGHT_STATUS_SUCCESS),
586 "albumName: " + counter.first + ", photo count: " + std::to_string(counter.second));
587 }
588 double meanCnt = albumPhotoCounter_.size() == 0 ? 0 : (double) totalCnt / albumPhotoCounter_.size();
589 MEDIA_INFO_LOG("Highlight photos max: %{public}d, mean: %{public}f", maxCnt, meanCnt);
590 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
591 .Report("Highlight Photos", std::to_string(HIGHLIGHT_STATUS_SUCCESS),
592 "max: " + std::to_string(maxCnt) + ", mean: " + std::to_string(meanCnt));
593
594 MEDIA_INFO_LOG("Highlight Restore successCnt_: %{public}d, duplicateCnt_: %{public}d, failCnt_: %{public}d",
595 successCnt_.load(), duplicateCnt_.load(), failCnt_.load());
596 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
597 .Report("Highlight Restore", std::to_string(HIGHLIGHT_STATUS_SUCCESS),
598 "successCnt_: " + std::to_string(successCnt_) + ", duplicateCnt_: " + std::to_string(duplicateCnt_) +
599 ", failCnt_: " + std::to_string(failCnt_));
600 MEDIA_ERR_LOG("EffectVideoTrack parse fail. totalCnt: %{public}d", tracksParseFailCnt_.load());
601 ErrorInfo errorInfo(RestoreError::PARSE_TRACK_FAILED, 0, "",
602 "EffectVideoTrack parse fail. totalCnt: " + std::to_string(tracksParseFailCnt_));
603 UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
604 }
605 } // namespace OHOS::Media