MediaTable.ets 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. import relationalStore from '@ohos.data.relationalStore';
  2. import { StrUtil } from '@pura/harmony-utils';
  3. import { VideoItem } from '../../viewmodel/VideoItem';
  4. import Logger from './Logger';
  5. import RdbUtils from './RdbUtils';
  6. import { Utility } from './Utility';
  7. export default class MediaTable {
  8. private accountTable = new RdbUtils(RdbUtils.MEDIA_TABLE.tableName, RdbUtils.MEDIA_TABLE.sqlCreate,
  9. RdbUtils.MEDIA_TABLE.columns);
  10. constructor(context:Context,callback: Function = () => {
  11. }) {
  12. this.accountTable.getRdbStore(context,callback);
  13. }
  14. getRdbStore(context:Context,callback: Function = () => {
  15. }) {
  16. this.accountTable.getRdbStore(context,callback);
  17. }
  18. insert(item: VideoItem, callback: Function,cover_api?:string) {
  19. const valueBucket: relationalStore.ValuesBucket = generateBucket(item);
  20. this.accountTable.insertData(valueBucket, callback,cover_api);
  21. }
  22. deleteData(item: VideoItem, callback: Function) {
  23. let predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  24. predicates.equalTo('id', item.id);
  25. this.accountTable.deleteData(predicates, callback);
  26. }
  27. deleteDataForParentPath(parentPath:string, callback: Function) {
  28. let predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  29. predicates.equalTo('parentPath', parentPath);
  30. this.accountTable.deleteData(predicates, callback);
  31. }
  32. public updatePixelMapPath(filePath: string, newPixelMapPath: string, callback: Function) {
  33. // Step 1: 构建查询条件验证文件存在性
  34. const queryPredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  35. queryPredicates.equalTo('filePath', filePath);
  36. // Step 2: 执行存在性验证
  37. this.accountTable.query(queryPredicates, (resultSet: relationalStore.ResultSet) => {
  38. if (resultSet.rowCount === 0) {
  39. callback(false, 'Error: Target file not found in database');
  40. resultSet.close();
  41. return;
  42. }
  43. resultSet.close();
  44. // Step 3: 构建更新条件与数据
  45. const updatePredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  46. updatePredicates.equalTo('filePath', filePath);
  47. const valueBucket: relationalStore.ValuesBucket = {
  48. pixelMapPath: newPixelMapPath
  49. };
  50. // Step 4: 执行原子化更新操作
  51. this.accountTable.updateData(updatePredicates, valueBucket, (success: boolean) => {
  52. callback(success, success ? null : 'Database update operation failed');
  53. });
  54. });
  55. }
  56. updateData(item: VideoItem, callback: Function) {
  57. const valueBucket: relationalStore.ValuesBucket = generateBucket(item);
  58. let predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  59. predicates.equalTo('id', item.id);
  60. this.accountTable.updateData(predicates, valueBucket, callback);
  61. }
  62. //编辑歌曲的信息更新数据库
  63. public updateMediaInfo(filePath: string, title: string, artist: string, album: string, callback: Function) {
  64. if (!callback || typeof callback !== 'function') {
  65. Logger.info(RdbUtils.RDB_TAG, 'updateMediaInfo() has no valid callback!');
  66. return;
  67. }
  68. if (!this.accountTable) {
  69. Logger.error(RdbUtils.RDB_TAG, 'RdbStore is not initialized.');
  70. callback(false);
  71. return;
  72. }
  73. // Step 1: Create a predicate to find the record by filePath
  74. const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  75. predicates.equalTo('filePath', filePath);
  76. // Step 2: Query the database to check if the record exists
  77. this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
  78. if (resultSet.rowCount === 0) {
  79. Logger.info(RdbUtils.RDB_TAG, `No record found with filePath ${filePath}.`);
  80. callback(false);
  81. resultSet.close();
  82. return;
  83. }
  84. // Step 3: Prepare the values to update
  85. const valuesToUpdate: relationalStore.ValuesBucket = {};
  86. if (title !== '') {
  87. valuesToUpdate.name = title;
  88. }
  89. if (artist !== '') {
  90. valuesToUpdate.artist = artist;
  91. }
  92. if (album !== '') {
  93. valuesToUpdate.album = album;
  94. }
  95. resultSet.close();
  96. // Step 4: Update the record if there are values to update
  97. if (Object.keys(valuesToUpdate).length > 0) {
  98. this.accountTable.updateData(predicates, valuesToUpdate, (success: boolean) => {
  99. callback(success, success ? null : 'Database update operation failed');
  100. });
  101. } else {
  102. Logger.info(RdbUtils.RDB_TAG, 'No fields to update.');
  103. callback(false);
  104. }
  105. });
  106. }
  107. //更新重命名数据操作
  108. public updateRename(newName: string, oldPath: string, newPath: string, callback: Function) {
  109. // Step 1: 查询原始记录
  110. const queryPredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  111. queryPredicates.equalTo('filePath', oldPath);
  112. this.accountTable.query(queryPredicates, (resultSet: relationalStore.ResultSet) => {
  113. if (resultSet.rowCount === 0) {
  114. callback(false, 'Error: File not found');
  115. return;
  116. }
  117. resultSet.goToFirstRow();
  118. // Step 3: 构建更新数据
  119. const currentName = resultSet.getString(resultSet.getColumnIndex('name'));
  120. const currentFileName = resultSet.getString(resultSet.getColumnIndex('fileName'));
  121. let obj: relationalStore.ValuesBucket = {};
  122. obj.id = newPath
  123. obj.filePath = newPath;
  124. if (currentName === currentFileName) {
  125. obj.name = newName;
  126. obj.fileName = newName;
  127. } else {
  128. obj.fileName = newName;
  129. }
  130. obj.mtype = resultSet.getDouble(resultSet.getColumnIndex('mtype'));
  131. obj.videoSize = resultSet.getDouble(resultSet.getColumnIndex('videoSize'));
  132. obj.cTime = resultSet.getString(resultSet.getColumnIndex('cTime'));
  133. obj.parentPath = resultSet.getString(resultSet.getColumnIndex('parentPath'));
  134. // obj.pixelMapToString = resultSet.getString(resultSet.getColumnIndex('pixelMapToString'));
  135. obj.artist = resultSet.getString(resultSet.getColumnIndex('artist'));
  136. obj.album = resultSet.getString(resultSet.getColumnIndex('album'));
  137. obj.isFav = resultSet.getDouble(resultSet.getColumnIndex('isFav'));
  138. obj.pixelMapPath = resultSet.getString(resultSet.getColumnIndex('pixelMapPath'));
  139. obj.duration = resultSet.getString(resultSet.getColumnIndex('duration'));
  140. obj.mimeType = resultSet.getString(resultSet.getColumnIndex('mimeType'));
  141. obj.trackCount = resultSet.getString(resultSet.getColumnIndex('trackCount'));
  142. obj.sampleRate = resultSet.getString(resultSet.getColumnIndex('sampleRate'));
  143. obj.lastPlayedStr = resultSet.getString(resultSet.getColumnIndex('lastPlayedStr'));
  144. obj.playCount = resultSet.getDouble(resultSet.getColumnIndex('playCount'));
  145. obj.lyricContent = resultSet.getString(resultSet.getColumnIndex('lyricContent'));
  146. const valueBucket: relationalStore.ValuesBucket = obj
  147. // Step 4: 执行更新
  148. const updatePredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  149. updatePredicates.equalTo('filePath', oldPath);
  150. this.accountTable.updateData(updatePredicates, valueBucket, (success: boolean) => {
  151. callback(success, success ? null : 'Update failed');
  152. });
  153. resultSet.close()
  154. });
  155. }
  156. // 根据isFav查询数据
  157. public queryByisFav(isFav: number, callback: (result: VideoItem[]) => void) {
  158. const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  159. predicates.equalTo('isFav', isFav);
  160. this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
  161. const result = this.parseResultSetToVideoItems(resultSet);
  162. callback(result);
  163. });
  164. }
  165. // 根据filePath更新isFav的值
  166. public updateIsFavByFilePath(filePath: string, isFav: number, callback: (success: boolean, error?: string) => void) {
  167. const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  168. predicates.equalTo('filePath', filePath);
  169. this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
  170. if (resultSet.rowCount === 0) {
  171. callback(false, 'Error: File not found');
  172. resultSet.close();
  173. return;
  174. }
  175. resultSet.close();
  176. const valueBucket: relationalStore.ValuesBucket = { isFav: isFav };
  177. this.accountTable.updateData(predicates, valueBucket, (success: boolean) => {
  178. callback(success, success ? '' : 'Update failed');
  179. });
  180. });
  181. }
  182. // 查询全部,或者某个id(查询的字段,回调,是否查询全部)
  183. query(id: number, callback: Function, isAll: boolean = true) {
  184. let predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  185. if (!isAll) {
  186. predicates.equalTo('id', id);
  187. }
  188. this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
  189. let count: number = resultSet.rowCount;
  190. if (count === 0 || typeof count === 'string') {
  191. console.log(`${RdbUtils.RDB_TAG}` + 'Query no results!');
  192. callback([]);
  193. } else {
  194. const result = this.parseResultSetToVideoItems(resultSet);
  195. callback(result);
  196. }
  197. });
  198. }
  199. // 新增方法:根据parentPath查询数据
  200. public queryByParentPath(path: string, callback: (result: VideoItem[]) => void) {
  201. try {
  202. const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  203. predicates.equalTo('parentPath', path);
  204. // 2. 执行查询并处理结果
  205. this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
  206. // 3. 复用已有的解析逻辑
  207. const result = this.parseResultSetToVideoItems(resultSet);
  208. callback(result);
  209. });
  210. }catch (err) {
  211. Logger.error(` onecold testtag queryByParentPath: ${err.code} - ${err.message}`);
  212. }
  213. // 1. 构建查询条件
  214. }
  215. // 查询所有艺术家及其歌曲(返回Map结构:artist -> VideoItem[])
  216. public queryArtistsWithSongs(callback: (result: Map<string, VideoItem[]>) => void) {
  217. // 1. 查询去重的艺术家列表(非空)
  218. const artistPredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  219. artistPredicates.isNotNull('artist').distinct();
  220. this.accountTable.query(artistPredicates, (resultSet: relationalStore.ResultSet) => {
  221. const artists: string[] = this.parseDistinctColumn(resultSet, 'artist');
  222. // 2. 遍历每个艺术家,查询其歌曲
  223. const resultMap = new Map<string, VideoItem[]>();
  224. let processedCount = 0;
  225. if (artists.length === 0) {
  226. callback(resultMap);
  227. return;
  228. }
  229. artists.forEach(artist => {
  230. const songPredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  231. songPredicates.equalTo('artist', artist);
  232. this.accountTable.query(songPredicates, (songResultSet: relationalStore.ResultSet) => {
  233. const songs = this.parseResultSetToVideoItems(songResultSet);
  234. resultMap.set(artist, songs);
  235. processedCount++;
  236. // 3. 全部查询完成后回调
  237. if (processedCount === artists.length) {
  238. callback(resultMap);
  239. }
  240. });
  241. });
  242. });
  243. }
  244. // 查询所有专辑及其歌曲(返回Map结构:album -> VideoItem[])
  245. public queryAlbumsWithSongs(callback: (result: Map<string, VideoItem[]>) => void) {
  246. // 1. 查询去重的专辑列表(非空)
  247. const albumPredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  248. albumPredicates.isNotNull('album').distinct();
  249. this.accountTable.query(albumPredicates, (resultSet: relationalStore.ResultSet) => {
  250. const albums: string[] = this.parseDistinctColumn(resultSet, 'album');
  251. // 2. 遍历每个专辑,查询其歌曲
  252. const resultMap = new Map<string, VideoItem[]>();
  253. let processedCount = 0;
  254. if (albums.length === 0) {
  255. callback(resultMap);
  256. return;
  257. }
  258. albums.forEach(album => {
  259. const songPredicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
  260. songPredicates.equalTo('album', album);
  261. this.accountTable.query(songPredicates, (songResultSet: relationalStore.ResultSet) => {
  262. const songs = this.parseResultSetToVideoItems(songResultSet);
  263. resultMap.set(album, songs);
  264. processedCount++;
  265. // 3. 全部查询完成后回调
  266. if (processedCount === albums.length) {
  267. callback(resultMap);
  268. }
  269. });
  270. });
  271. });
  272. }
  273. // 解析去重列数据(如artist/album)
  274. private parseDistinctColumn(resultSet: relationalStore.ResultSet, columnName: string): string[] {
  275. const uniqueValues = new Set<string>(); // 使用Set特性自动去重
  276. if (resultSet.rowCount > 0) {
  277. resultSet.goToFirstRow();
  278. for (let i = 0; i < resultSet.rowCount; i++) {
  279. const value = resultSet.getString(resultSet.getColumnIndex(columnName))?.trim(); // 处理空格
  280. if (value) { // 过滤空值
  281. uniqueValues.add(value);
  282. }
  283. if (i < resultSet.rowCount - 1) { // 避免最后一行越界
  284. resultSet.goToNextRow();
  285. }
  286. }
  287. }
  288. resultSet.close();
  289. return Array.from(uniqueValues); // Set转数组
  290. }
  291. // 将ResultSet解析为VideoItem数组(复用原有逻辑)
  292. private parseResultSetToVideoItems(resultSet: relationalStore.ResultSet): VideoItem[] {
  293. const items: VideoItem[] = [];
  294. try {
  295. // 逆向遍历方案(规避鸿蒙API特性)
  296. while (resultSet.goToNextRow()) { // 自动边界检查
  297. const item = this.buildVideoItem(resultSet);
  298. // let id = resultSet.getString(resultSet.getColumnIndex('id'));
  299. // let name = resultSet.getString(resultSet.getColumnIndex('name'));
  300. // let filePath = resultSet.getString(resultSet.getColumnIndex('filePath'));
  301. // let type = resultSet.getDouble(resultSet.getColumnIndex('mtype'));
  302. // let videoSize = resultSet.getDouble(resultSet.getColumnIndex('videoSize'));
  303. // let cTime = resultSet.getString(resultSet.getColumnIndex('cTime'));
  304. // let size = resultSet.getString(resultSet.getColumnIndex('size'));
  305. // let parentPath = resultSet.getString(resultSet.getColumnIndex('parentPath'));
  306. //
  307. // let pixelMapToString = resultSet.getString(resultSet.getColumnIndex('pixelMapToString'));
  308. // let artist = resultSet.getString(resultSet.getColumnIndex('artist'));
  309. // let album = resultSet.getString(resultSet.getColumnIndex('album'));
  310. // let fileName = resultSet.getString(resultSet.getColumnIndex('fileName'));
  311. // let item = new VideoItem(name, id, filePath, type, videoSize, cTime,
  312. // undefined,size,pixelMapToString,artist,album,fileName);
  313. items.push(item);
  314. }
  315. // 释放数据集的内存
  316. resultSet.close();
  317. } catch (err) {
  318. Logger.error(` onecold testtag parseResultSetToVideoItems: ${err.code} - ${err.message}`);
  319. }
  320. return items;
  321. }
  322. private buildVideoItem(rs: relationalStore.ResultSet): VideoItem {
  323. // 添加空值保护
  324. const safeGet = (col: string) => rs.getColumnIndex(col) >= 0 ? rs.getString(rs.getColumnIndex(col)) : '';
  325. let item = new VideoItem(
  326. safeGet('name'),
  327. safeGet('id'),
  328. safeGet('filePath'),
  329. rs.getDouble(rs.getColumnIndex('mtype')) || 0,
  330. rs.getDouble(rs.getColumnIndex('videoSize')) || 0,safeGet('cTime'),undefined,safeGet('size'),
  331. safeGet('pixelMapPath'),safeGet('artist'),
  332. safeGet('album'),safeGet('fileName')
  333. );
  334. item.isFav = rs.getDouble(rs.getColumnIndex('isFav'));
  335. item.duration = safeGet('duration');
  336. item.mimeType = safeGet('mimeType');
  337. item.trackCount = safeGet('trackCount');
  338. item.sampleRate = safeGet('sampleRate');
  339. item.lastPlayedStr =safeGet('lastPlayedStr');
  340. // item.playCount = rs.getDouble(rs.getColumnIndex('playCount'));
  341. item.lyricContent = safeGet('lyricContent')
  342. return item
  343. }
  344. }
  345. function generateBucket(item: VideoItem): relationalStore.ValuesBucket {
  346. let obj: relationalStore.ValuesBucket = {};
  347. obj.id = item.id
  348. obj.name = item.name;
  349. obj.filePath = item.filePath;
  350. obj.mtype = item.type;
  351. obj.videoSize = item.videoSize;
  352. obj.cTime = item.cTime;
  353. obj.parentPath = item.parentPath;
  354. obj.isFav = item.isFav;
  355. // if(item.pixelMapToString){
  356. // obj.pixelMapToString = item.pixelMapToString;
  357. // }
  358. if(item.artist){
  359. obj.artist = item.artist;
  360. }
  361. if(item.album){
  362. obj.album = item.album;
  363. }
  364. if(item.fileName){
  365. obj.fileName = item.fileName;
  366. }
  367. if(item.size){
  368. obj.size = item.size;
  369. }
  370. if(item.pixelMapPath){
  371. obj.pixelMapPath = item.pixelMapPath;
  372. }
  373. if(item.duration){
  374. obj.duration = item.duration;
  375. }
  376. if(item.mimeType){
  377. obj.mimeType = item.mimeType;
  378. }
  379. if(item.trackCount){
  380. obj.trackCount = item.trackCount;
  381. }
  382. if(item.sampleRate){
  383. obj.sampleRate = item.sampleRate;
  384. }
  385. if(item.lastPlayedStr){
  386. obj.lastPlayedStr = item.lastPlayedStr;
  387. }
  388. if(item.playCount){
  389. obj.playCount = item.playCount;
  390. }
  391. if(item.lyricContent){
  392. obj.lyricContent = item.lyricContent;
  393. }
  394. return obj;
  395. }