• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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