DeleteComptent.ets 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. import { common } from '@kit.AbilityKit';
  2. import { CommonConstants } from '../common/constants/CommonConstants';
  3. import { VideoItem } from '../viewmodel/VideoItem';
  4. import { AppUtil, ArrayUtil, FileUtil, LogUtil, PreferencesUtil, StrUtil, ToastUtil } from '@pura/harmony-utils';
  5. import MediaTable from '../common/util/MediaTable';
  6. import PlaylistTable from '../common/util/PlaylistTable';
  7. import { EventConstants } from '../common/constants/EventConstants';
  8. import { emitter } from '@kit.BasicServicesKit';
  9. import { taskpool } from '@kit.ArkTS';
  10. import PermissionUtil from '../common/util/PermissionUtil'
  11. // 批量删除
  12. @Component
  13. export struct DeleteComptent {
  14. @State isDeleteYuan: boolean = true
  15. @State isDeletePicture: boolean = true
  16. @State isDeleteLrc: boolean = true
  17. @State onlyRemoveFromPlaylist: boolean = false
  18. @State packName: string = ''
  19. @State isDeleting: boolean = false // 删除状态
  20. @State deleteProgress: number = 0 // 删除进度 (0-100)
  21. @State currentDeleteFile: string = '' // 当前删除的文件名
  22. onDeleteResult = (_result: boolean) => {
  23. }
  24. onCancel = () => {
  25. }
  26. @Prop selectedFiles: Array<VideoItem>
  27. @Prop isPlaylistMode: boolean = false
  28. @Prop playlistId: string = ''
  29. @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
  30. context = this.getUIContext().getHostContext() as common.UIAbilityContext
  31. async aboutToAppear() {
  32. this.packName = AppUtil.getBundleName()
  33. this.isDeleteYuan = PreferencesUtil.getBooleanSync('isDeleteYuan', true);
  34. this.isDeletePicture = PreferencesUtil.getBooleanSync('isDeletePicture', true);
  35. this.isDeleteLrc = PreferencesUtil.getBooleanSync('isDeleteLrc', true)
  36. if (!this.isPlaylistMode) {
  37. this.onlyRemoveFromPlaylist = false
  38. }
  39. }
  40. private hasOnlyDirectories(): boolean {
  41. return this.selectedFiles.length > 0 &&
  42. this.selectedFiles.every(item => item.type === CommonConstants.TYPE_IS_DIR)
  43. }
  44. build() {
  45. Column() {
  46. if (this.isDeleting) {
  47. // 删除进度界面
  48. Column() {
  49. Text('正在删除文件').fontSize(18).fontColor(Color.Red).margin({ top: 20, bottom: 15 })
  50. // 当前文件名显示
  51. if (this.currentDeleteFile) {
  52. Text(`正在删除: ${this.currentDeleteFile}`)
  53. .fontSize(14)
  54. .fontColor($r('app.color.text_color'))
  55. .maxLines(2)
  56. .textOverflow({ overflow: TextOverflow.Ellipsis })
  57. .width('90%')
  58. .textAlign(TextAlign.Start)
  59. .margin({ bottom: 15 })
  60. }
  61. // 进度条
  62. Column() {
  63. Row() {
  64. Text(`${Math.round(this.deleteProgress)}%`)
  65. .fontSize(12)
  66. .fontColor($r('app.color.text_color'))
  67. Blank()
  68. Text(`${Math.round(this.deleteProgress * this.selectedFiles.length / 100)}/${this.selectedFiles.length}`)
  69. .fontSize(12)
  70. .fontColor($r('app.color.text_color'))
  71. }
  72. .width('90%')
  73. .margin({ bottom: 8 })
  74. Progress({
  75. value: this.deleteProgress,
  76. total: 100,
  77. type: ProgressType.Linear
  78. })
  79. .width('90%')
  80. .height(8)
  81. .color(this.themeColor)
  82. .backgroundColor('#E0E0E0')
  83. .borderRadius(4)
  84. }
  85. .width('100%')
  86. .alignItems(HorizontalAlign.Center)
  87. .margin({ bottom: 20 })
  88. // 取消按钮
  89. Button('取消删除')
  90. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
  91. .padding(15)
  92. .width(120)
  93. .onClick(() => {
  94. this.onCancel()
  95. })
  96. .backgroundColor($r('app.color.silvery'))
  97. .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
  98. .fontColor(Color.Black)
  99. }
  100. .backgroundColor($r('app.color.start_window_background'))
  101. .backgroundBlurStyle(BlurStyle.Regular)
  102. .padding(20)
  103. } else {
  104. // 原始删除确认界面
  105. Column() {
  106. Text('温馨提醒').fontSize(20).margin({ top: 10, bottom: 10 })
  107. Text('是否删除这些文件?').fontSize(16).margin({ top: 10, bottom: 10 })
  108. Column() {
  109. // 只移除歌单选项(歌单场景)
  110. Button({ type: ButtonType.Capsule, stateEffect: true }) {
  111. Row() {
  112. SymbolGlyph($r('sys.symbol.music_note_list'))
  113. .fontSize(20)
  114. .fontColor([this.themeColor])
  115. .alignSelf(ItemAlign.Center)
  116. .margin({ left: 15 })
  117. Text("只移除歌单")
  118. .fontSize(16)
  119. .layoutWeight(1)
  120. .margin({ left: 10 })
  121. Toggle({ type: ToggleType.Checkbox, isOn: this.onlyRemoveFromPlaylist })
  122. .onChange((isOn: boolean) => {
  123. this.onlyRemoveFromPlaylist = isOn;
  124. if (isOn) {
  125. this.isDeleteYuan = false
  126. this.isDeletePicture = false
  127. this.isDeleteLrc = false
  128. }
  129. })
  130. .margin({ right: 28 })
  131. .selectedColor(this.themeColor)
  132. }
  133. }
  134. .backgroundColor(Color.Transparent)
  135. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
  136. .onClick(() => {
  137. this.onlyRemoveFromPlaylist = !this.onlyRemoveFromPlaylist
  138. if (this.onlyRemoveFromPlaylist) {
  139. this.isDeleteYuan = false
  140. this.isDeletePicture = false
  141. this.isDeleteLrc = false
  142. }
  143. })
  144. .width('100%')
  145. .padding(10)
  146. .margin({ left: 18 })
  147. .visibility(this.isPlaylistMode ? Visibility.Visible : Visibility.None)
  148. // 删除源文件选项
  149. Button({ type: ButtonType.Capsule, stateEffect: true }) {
  150. Row() {
  151. SymbolGlyph($r('sys.symbol.doc_text'))
  152. .fontSize(20)
  153. .fontColor([this.themeColor])
  154. .alignSelf(ItemAlign.Center)
  155. .margin({ left: 15 })
  156. Text("删除源文件")
  157. .fontSize(16)
  158. .layoutWeight(1)
  159. .margin({ left: 10 })
  160. Toggle({ type: ToggleType.Checkbox, isOn: this.isDeleteYuan })
  161. .onChange((isOn: boolean) => {
  162. this.isDeleteYuan = isOn;
  163. PreferencesUtil.put('isDeleteYuan', this.isDeleteYuan)
  164. })
  165. .margin({ right: 28 })
  166. .selectedColor(this.themeColor)
  167. }
  168. }
  169. .backgroundColor(Color.Transparent)
  170. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
  171. .onClick(() => {
  172. this.isDeleteYuan = !this.isDeleteYuan
  173. })
  174. .width('100%')
  175. .padding(10)
  176. .margin({ left: 18 })
  177. .visibility(this.onlyRemoveFromPlaylist ? Visibility.None : Visibility.Visible)
  178. // 删除封面选项
  179. Button({ type: ButtonType.Capsule, stateEffect: true }) {
  180. Row() {
  181. SymbolGlyph($r('sys.symbol.picture'))
  182. .fontSize(20)
  183. .fontColor([this.themeColor])
  184. .alignSelf(ItemAlign.Center)
  185. .margin({ left: 15 })
  186. Text("删除封面文件")
  187. .fontSize(16)
  188. .layoutWeight(1)
  189. .margin({ left: 10 })
  190. Toggle({ type: ToggleType.Checkbox, isOn: this.isDeletePicture })
  191. .onChange((isOn: boolean) => {
  192. this.isDeletePicture = isOn;
  193. PreferencesUtil.put('isDeletePicture', this.isDeletePicture)
  194. })
  195. .margin({ right: 28 })
  196. .selectedColor(this.themeColor)
  197. }
  198. }
  199. .backgroundColor(Color.Transparent)
  200. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
  201. .onClick(() => {
  202. this.isDeletePicture = !this.isDeletePicture
  203. })
  204. .width('100%')
  205. .padding(10)
  206. .margin({ left: 18 })
  207. .visibility(this.onlyRemoveFromPlaylist ? Visibility.None : Visibility.Visible)
  208. // 删除歌词选项
  209. Button({ type: ButtonType.Capsule, stateEffect: true }) {
  210. Row() {
  211. SymbolGlyph($r('sys.symbol.input_mode'))
  212. .fontSize(20)
  213. .fontColor([this.themeColor])
  214. .alignSelf(ItemAlign.Center)
  215. .margin({ left: 15 })
  216. Text("删除歌词文件")
  217. .fontSize(16)
  218. .layoutWeight(1)
  219. .margin({ left: 10 })
  220. Toggle({ type: ToggleType.Checkbox, isOn: this.isDeleteLrc })
  221. .onChange((isOn: boolean) => {
  222. this.isDeleteLrc = isOn;
  223. PreferencesUtil.put('isDeleteLrc', this.isDeleteLrc)
  224. })
  225. .margin({ right: 28 })
  226. .selectedColor(this.themeColor)
  227. }
  228. }
  229. .backgroundColor(Color.Transparent)
  230. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
  231. .onClick(() => {
  232. this.isDeleteLrc = !this.isDeleteLrc
  233. })
  234. .width('100%')
  235. .padding(10)
  236. .margin({ left: 18, bottom: 10 })
  237. .visibility(this.onlyRemoveFromPlaylist ? Visibility.None : Visibility.Visible)
  238. }
  239. .visibility(this.hasOnlyDirectories() ? Visibility.None : Visibility.Visible)
  240. Flex({ justifyContent: FlexAlign.SpaceAround }) {
  241. Button($r('app.string.cancel'))
  242. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
  243. .padding(15)
  244. .width(120)
  245. .onClick(() => {
  246. this.onCancel()
  247. })
  248. .backgroundColor($r('app.color.silvery'))
  249. .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
  250. .fontColor(Color.Black)
  251. Button($r('app.string.sure'))
  252. .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
  253. .padding(15)
  254. .width(120)
  255. .onClick(() => {
  256. this.doDeleteTask()
  257. })
  258. .backgroundColor($r('app.color.silvery'))
  259. .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
  260. .fontColor(Color.Red)
  261. }.margin({ bottom: 10 })
  262. }
  263. .backgroundColor($r('app.color.start_window_background'))
  264. .backgroundBlurStyle(BlurStyle.Regular)
  265. }
  266. }
  267. }
  268. doDeleteTask(){
  269. if (this.onlyRemoveFromPlaylist && StrUtil.isEmpty(this.playlistId)) {
  270. ToastUtil.showToast('当前歌单信息无效')
  271. return
  272. }
  273. // 设置删除状态
  274. this.isDeleting = true;
  275. this.deleteProgress = 0;
  276. this.currentDeleteFile = '';
  277. const totalFiles = this.selectedFiles.length;
  278. let currentFileIndex = 0;
  279. // 创建进度监控定时器
  280. let progressTimer: number = setInterval(() => {
  281. // 基于时间模拟进度
  282. if (currentFileIndex < totalFiles) {
  283. this.deleteProgress = (currentFileIndex / totalFiles) * 95; // 最高到95%
  284. this.currentDeleteFile = this.selectedFiles[currentFileIndex]?.name || '';
  285. currentFileIndex++;
  286. }
  287. if (this.deleteProgress >= 95) {
  288. clearInterval(progressTimer);
  289. }
  290. }, 300); // 每300ms更新一次,模拟删除进度
  291. const task = this.onlyRemoveFromPlaylist ?
  292. new taskpool.Task(
  293. removeSongsFromPlaylistOnly,
  294. JSON.stringify(this.selectedFiles),
  295. this.context,
  296. this.playlistId
  297. ) :
  298. new taskpool.Task(
  299. deleteMultipleFilesWithProgress,
  300. JSON.stringify(this.selectedFiles),
  301. this.isDeleteYuan, this.isDeletePicture, this.isDeleteLrc, this.context, this.packName
  302. );
  303. taskpool.execute(task, taskpool.Priority.HIGH).then((result) => {
  304. clearInterval(progressTimer);
  305. this.deleteProgress = 100;
  306. this.currentDeleteFile = '删除完成';
  307. setTimeout(() => {
  308. if(result){
  309. this.onDeleteResult(true)
  310. }else {
  311. this.onDeleteResult(false)
  312. }
  313. },500)
  314. }).catch((error:Error) => {
  315. clearInterval(progressTimer);
  316. console.error('heanup DeleteComptent: delete failed:', (error as Error).message);
  317. this.isDeleting = false;
  318. });
  319. }
  320. }
  321. // 仅从当前歌单移除歌曲
  322. @Concurrent
  323. async function removeSongsFromPlaylistOnly(
  324. selectedFilesStr:string,
  325. context:Context,
  326. playlistId:string
  327. ) {
  328. const selectedFiles: VideoItem[] = JSON.parse(selectedFilesStr)
  329. if (!ArrayUtil.isNotEmpty(selectedFiles)) {
  330. return true
  331. }
  332. if (StrUtil.isEmpty(playlistId)) {
  333. LogUtil.error('heanup DeleteComptent', 'removeSongsFromPlaylistOnly: playlistId 为空')
  334. return false
  335. }
  336. const playlistTable: PlaylistTable = new PlaylistTable(context)
  337. let hasPlaylistChanges = false
  338. let hasError = false
  339. for (let i = 0; i < selectedFiles.length; i++) {
  340. const item = selectedFiles[i]
  341. if (!item.filePath) {
  342. continue
  343. }
  344. try {
  345. const removed = await playlistTable.removeSongFromPlaylist(playlistId, item.filePath)
  346. if (removed) {
  347. hasPlaylistChanges = true
  348. } else {
  349. hasError = true
  350. }
  351. } catch (error) {
  352. hasError = true
  353. LogUtil.error('heanup DeleteComptent', `removeSongsFromPlaylistOnly error: ${(error as Error).message}`)
  354. }
  355. await new Promise<void>(resolve => setTimeout(resolve, 120))
  356. }
  357. if (hasPlaylistChanges) {
  358. const eventRefresh: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYLIST_REFRESH }
  359. emitter.emit(eventRefresh, {})
  360. emitter.emit({ eventId: EventConstants.EVENT_PLAYLIST_REFRESH_SORT }, {})
  361. }
  362. return !hasError
  363. }
  364. //多选删除文件(带进度显示的新版本)
  365. @Concurrent
  366. async function deleteMultipleFilesWithProgress(
  367. selectedFilesStr:string,
  368. isDeleteYuan:boolean,
  369. isDeletePicture:boolean,
  370. isDeleteLrc:boolean,
  371. context:Context,
  372. packName:string
  373. ) {
  374. const selectedFiles: VideoItem[] = JSON.parse(selectedFilesStr)
  375. if (ArrayUtil.isNotEmpty(selectedFiles)) {
  376. const table: MediaTable = new MediaTable(context)
  377. const playlistTable: PlaylistTable = new PlaylistTable(context)
  378. // 初始化数据库
  379. await new Promise<void>((resolve, reject) => {
  380. table.getRdbStore(context, (err:Error) => {
  381. err ? reject(err) : resolve();
  382. });
  383. });
  384. let hasPlaylistChanges = false; // 标记是否有歌单变化
  385. const totalFiles = selectedFiles.length;
  386. for (let i = 0; i < selectedFiles.length; i++) {
  387. const item = selectedFiles[i];
  388. console.info('heanup DeleteComptent: deleting file ' + (i + 1) + '/' + totalFiles + ': ' + item.name);
  389. if (item.type === CommonConstants.TYPE_IS_DIR) {
  390. // 删除目录
  391. await new Promise<void>((resolve) => {
  392. table.deleteDataForParentPath(item.filePath, async () => {
  393. try {
  394. await FileUtil.rmdir(item.filePath);
  395. console.info('heanup DeleteComptent: directory deleted: ' + item.filePath);
  396. } catch (error) {
  397. console.error('heanup DeleteComptent: directory delete error: ' + (error as Error).message);
  398. }
  399. resolve();
  400. });
  401. });
  402. } else {
  403. // 删除文件
  404. await new Promise<void>((resolve) => {
  405. table.deleteData(item, async () => {
  406. try {
  407. // 删除源文件
  408. if(isDeleteYuan && item.filePath.toLowerCase().includes(packName)){
  409. await FileUtil.unlink(item.filePath);
  410. console.info('heanup DeleteComptent: source file deleted: ' + item.filePath);
  411. }
  412. // 删除封面文件
  413. if (isDeletePicture && item.pixelMapPath) {
  414. const picPath = FileUtil.getFilePath(item.pixelMapPath);
  415. if (FileUtil.accessSync(picPath)) {
  416. await FileUtil.unlink(picPath);
  417. console.info('heanup DeleteComptent: cover file deleted: ' + picPath);
  418. }
  419. }
  420. // 删除歌词文件
  421. if(isDeleteLrc) {
  422. const lyricPath = item.filePath?.replace(/\.[^/.]+$/, ".lrc");
  423. if (lyricPath && item.filePath.toLowerCase().includes(packName) && FileUtil.accessSync(lyricPath)) {
  424. await FileUtil.unlink(lyricPath);
  425. console.info('heanup DeleteComptent: lyric file deleted: ' + lyricPath);
  426. }
  427. }
  428. } catch (error) {
  429. console.error('heanup DeleteComptent: file delete error: ' + (error as Error).message);
  430. }
  431. resolve();
  432. });
  433. });
  434. // 从歌单中移除歌曲
  435. LogUtil.info('heanup DeleteComptent', `准备从歌单中移除歌曲: ${item.name}, filePath: ${item.filePath}`);
  436. if (item.filePath) {
  437. try {
  438. const affectedPlaylists = await playlistTable.removeSongFromAllPlaylists(item.filePath);
  439. LogUtil.info('heanup DeleteComptent', `removeSongFromAllPlaylists 返回了 ${affectedPlaylists.length} 个受影响的歌单`);
  440. if (affectedPlaylists.length > 0) {
  441. hasPlaylistChanges = true;
  442. LogUtil.info('heanup DeleteComptent', `歌曲已从 ${affectedPlaylists.length} 个歌单中移除: ${item.name}`);
  443. } else {
  444. LogUtil.info('heanup DeleteComptent', `歌曲不在任何歌单中: ${item.name}`);
  445. }
  446. } catch (error) {
  447. LogUtil.error('heanup DeleteComptent', `从歌单移除歌曲失败: ${(error as Error).message}`);
  448. }
  449. } else {
  450. LogUtil.warn('heanup DeleteComptent', `歌曲 ${item.name} 的 filePath 为空`);
  451. }
  452. }
  453. // 短暂延迟,让用户能看到进度变化
  454. await new Promise<void>(resolve => setTimeout(resolve, 200));
  455. }
  456. // 如果有歌单变化,发送刷新事件
  457. if (hasPlaylistChanges) {
  458. const eventRefresh: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYLIST_REFRESH };
  459. emitter.emit(eventRefresh, {});
  460. LogUtil.info('heanup DeleteComptent', '已发送歌单刷新事件,更新歌单数量');
  461. }
  462. }
  463. return true
  464. }
  465. // 保留原始删除函数作为备用
  466. @Concurrent
  467. async function deleteMultipleFiles(
  468. selectedFilesStr:string,
  469. isDeleteYuan:boolean,
  470. isDeletePicture:boolean,
  471. isDeleteLrc:boolean,
  472. context:Context,
  473. packName:string
  474. ) {
  475. const selectedFiles: VideoItem[] = JSON.parse(selectedFilesStr)
  476. if (ArrayUtil.isNotEmpty(selectedFiles)) {
  477. const table: MediaTable = new MediaTable(context)
  478. const playlistTable: PlaylistTable = new PlaylistTable(context)
  479. // 初始化数据库
  480. await new Promise<void>((resolve, reject) => {
  481. table.getRdbStore(context, (err:Error) => {
  482. err ? reject(err) : resolve();
  483. });
  484. });
  485. let hasPlaylistChanges = false; // 标记是否有歌单变化
  486. for (const item of selectedFiles) {
  487. console.info('onecold delete filePath = ' + item.filePath);
  488. if (item.type === CommonConstants.TYPE_IS_DIR) {
  489. table.deleteDataForParentPath(item.filePath, () => {
  490. FileUtil.rmdir(item.filePath).then(() => {
  491. return true
  492. }).catch((error:Error) => {
  493. console.error((error as Error).message);
  494. return false
  495. });
  496. });
  497. } else {
  498. table.deleteData(item, async () => {
  499. if(isDeleteYuan){
  500. if(item.filePath.toLowerCase().includes(packName)){
  501. await FileUtil.unlink(item.filePath)
  502. }
  503. }
  504. console.info(`onecold 封面文件=: ${item.pixelMapPath}`);
  505. if (isDeletePicture && item.pixelMapPath) {
  506. const picPath = FileUtil.getFilePath(item.pixelMapPath)//获取图
  507. if (FileUtil.accessSync(picPath)) {
  508. await FileUtil.unlink(picPath);
  509. console.info(`onecold 封面文件已删除: ${picPath}`);
  510. }
  511. }
  512. const lyricPath = item.filePath?.replace(/\.[^/.]+$/, ".lrc");
  513. console.info(`onecold 歌词文件=: ${lyricPath}`);
  514. if(isDeleteLrc) {
  515. if (lyricPath&&item.filePath.toLowerCase().includes(packName) && FileUtil.accessSync(lyricPath)) {
  516. await FileUtil.unlink(lyricPath);
  517. console.info( `onecold 歌词文件已删除: ${lyricPath}`);
  518. }
  519. }
  520. // this.onDeleteResult(true,item)
  521. });
  522. // 先从所有歌单中移除这首歌(如果存在的话)
  523. LogUtil.info('heanup DeleteComptent', `准备从歌单中移除歌曲: ${item.name}, filePath: ${item.filePath}`);
  524. if (item.filePath) {
  525. try {
  526. const affectedPlaylists = await playlistTable.removeSongFromAllPlaylists(item.filePath);
  527. LogUtil.info('heanup DeleteComptent', `removeSongFromAllPlaylists 返回了 ${affectedPlaylists.length} 个受影响的歌单`);
  528. if (affectedPlaylists.length > 0) {
  529. hasPlaylistChanges = true;
  530. LogUtil.info('heanup DeleteComptent', `歌曲已从 ${affectedPlaylists.length} 个歌单中移除: ${item.name}`);
  531. } else {
  532. LogUtil.info('heanup DeleteComptent', `歌曲不在任何歌单中: ${item.name}`);
  533. }
  534. } catch (error) {
  535. LogUtil.error('heanup DeleteComptent', `从歌单移除歌曲失败: ${(error as Error).message}`);
  536. }
  537. } else {
  538. LogUtil.warn('heanup DeleteComptent', `歌曲 ${item.name} 的 filePath 为空`);
  539. }
  540. }
  541. }
  542. // 如果有歌单变化,发送刷新事件
  543. if (hasPlaylistChanges) {
  544. const eventRefresh: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYLIST_REFRESH };
  545. emitter.emit(eventRefresh, {});
  546. LogUtil.info('heanup DeleteComptent', '已发送歌单刷新事件,更新歌单数量');
  547. }
  548. }
  549. return true
  550. }