|
|
@@ -1,7 +1,7 @@
|
|
|
import TitleBar from './TitleBar'
|
|
|
import { curves, display, PiPWindow, promptAction, router, SymbolGlyphModifier, window } from '@kit.ArkUI';
|
|
|
import { VideoItem } from '../viewmodel/VideoItem';
|
|
|
-import { stringForTime } from '../common/util/CommUtils';
|
|
|
+import { Playlist } from '../viewmodel/Playlist';
|
|
|
import { LengthMetrics, SegmentButton,borderRadiuses, SegmentButtonOptions } from '@kit.ArkUI';
|
|
|
import {
|
|
|
AppUtil,
|
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
import { imagePathToPixelMap } from '../common/util/CommUtils';
|
|
|
import { unifiedDataChannel, uniformDataStruct, uniformTypeDescriptor } from '@kit.ArkData';
|
|
|
import { CommonConstants } from '../common/constants/CommonConstants';
|
|
|
+import { EventConstants } from '../common/constants/EventConstants';
|
|
|
import Logger from '../common/util/Logger';
|
|
|
import { photoAccessHelper } from '@kit.MediaLibraryKit';
|
|
|
import { BusinessError, emitter } from '@kit.BasicServicesKit';
|
|
|
@@ -82,13 +83,27 @@ import { TextNodeController } from './PipLyricTextBuilder';
|
|
|
import { IndexerView } from './IndexerView';
|
|
|
import { KeyCode } from '@kit.InputKit';
|
|
|
import { KnockController } from '../controller/KnockController';
|
|
|
-import { DeleteComptent } from '../view/DeleteComptent'
|
|
|
+import { DeleteComptent } from '../view/DeleteComptent';
|
|
|
import { ABLoopComptent } from '../view/ABLoopComptent';
|
|
|
import { FixMessyView } from '../view/FixMessyView';
|
|
|
import { parseCueFile,CueTrack,CueInfo } from '../common/util/CueUtils';
|
|
|
import { CueComptent } from '../view/CueComptent';
|
|
|
+import PlaylistTable from '../common/util/PlaylistTable';
|
|
|
+import { showAddToPlaylistDialog } from '../dialog/AddToPlaylistDialog';
|
|
|
+import { showCreatePlaylistDialog } from '../dialog/PlaylistDialog';
|
|
|
const TAG = 'LocalMusic';
|
|
|
|
|
|
+/**
|
|
|
+ * 歌单播放事件数据
|
|
|
+ */
|
|
|
+interface PlaylistEventData {
|
|
|
+ playlistId: string;
|
|
|
+ playlistName: string;
|
|
|
+ songCount: number;
|
|
|
+ startIndex: number;
|
|
|
+ songFilePaths: string[];
|
|
|
+}
|
|
|
+
|
|
|
const DEFAULT_INDEX =
|
|
|
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
|
|
'X', 'Y', 'Z']
|
|
|
@@ -147,10 +162,9 @@ const ITEM_HEIGHT_BIG: number = 78; // 列表项大高度
|
|
|
@Preview
|
|
|
@Component
|
|
|
export struct LocalMusic {
|
|
|
- @State isRefreshing: boolean = false;
|
|
|
- @State maxRefreshingHeight: number = 100.0;
|
|
|
- private contentNode?: ComponentContent<Object> = undefined;
|
|
|
- @State ratioL: number = 1;
|
|
|
+ @Consume currentSongList: Array<VideoItem>//当前歌单
|
|
|
+ @Consume currentSongListName:string //当前歌单名称
|
|
|
+ @Consume @Watch('onIDChange') currentSongListID:string //当前歌单ID
|
|
|
@State mediaKuCount: number = 0;
|
|
|
@State albumCount: number = 0;
|
|
|
@State artistCount: number = 0;
|
|
|
@@ -179,6 +193,8 @@ export struct LocalMusic {
|
|
|
@Consume isHistory: boolean
|
|
|
static readonly HISTORY_MUSIC: string = 'music_historyList';
|
|
|
private table: MediaTable = new MediaTable(getContext(this))
|
|
|
+ private playlistTable: PlaylistTable | null = null
|
|
|
+ @State allPlaylists: Playlist[] = []
|
|
|
@State isZero: boolean = false
|
|
|
@State fileList: Array<string> = []
|
|
|
@State dirList: Array<VideoItem> = []
|
|
|
@@ -279,6 +295,17 @@ export struct LocalMusic {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ //歌单id发生变化的时候回调
|
|
|
+ onIDChange(){
|
|
|
+ if(this.modeType==4){
|
|
|
+ this.titleBarModel.setLeftIconMainNoAnimate($r('app.media.menu'))
|
|
|
+ this.updateListData(this.currentSongList, true)
|
|
|
+ this.titleBarModel.setTitleName(this.currentSongListName)
|
|
|
+ this.isShowTitleBar = false
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
onModeChange() {
|
|
|
this.isFavMusic = false
|
|
|
if (this.modeType === 2 || this.modeType === 3) {
|
|
|
@@ -287,6 +314,7 @@ export struct LocalMusic {
|
|
|
this.titleBarModel.setRightIcon(($r('app.media.add')))
|
|
|
}
|
|
|
LogUtil.info('onecold onModeChange = ' + this.modeType)
|
|
|
+ this.isShowTitleBar = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_TITLTBAR, true)
|
|
|
switch (this.modeType) {
|
|
|
case 0:
|
|
|
this.getSortedFiles(this.currentPath)
|
|
|
@@ -307,6 +335,12 @@ export struct LocalMusic {
|
|
|
this.updateListData(this.albumList)
|
|
|
this.titleBarModel.setTitleName(Utility.resourceToString(this.context, $r('app.string.album')))
|
|
|
break
|
|
|
+ case 4://歌单
|
|
|
+ this.titleBarModel.setLeftIconMainNoAnimate($r('app.media.menu'))
|
|
|
+ this.updateListData(this.currentSongList, true)
|
|
|
+ this.titleBarModel.setTitleName(this.currentSongListName)
|
|
|
+ this.isShowTitleBar = false
|
|
|
+ break
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -506,6 +540,9 @@ export struct LocalMusic {
|
|
|
|
|
|
// 组件生命周期
|
|
|
aboutToAppear() {
|
|
|
+ // 初始化 PlaylistTable
|
|
|
+ this.playlistTable = new PlaylistTable(getContext(this))
|
|
|
+
|
|
|
this.sonTwoFingerType = PreferencesUtil.getNumberSync('sonTwoFingerType', 3);
|
|
|
this.columns = PreferencesUtil.getNumberSync('lastColumns', 2);
|
|
|
if(PreferencesUtil.getBooleanSync('isFirstTiped',true)){
|
|
|
@@ -529,7 +566,7 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
|
|
|
|
- let eventMusic: emitter.InnerEvent = { eventId: 2 }
|
|
|
+ let eventMusic: emitter.InnerEvent = { eventId: EventConstants.EVENT_AUDIO_OPEN }
|
|
|
// 监听广播事件(打开其他应用处理)
|
|
|
emitter.on(eventMusic, (eventData: emitter.EventData) => {
|
|
|
this.saveVideoDatas([eventData.data?.message], true)
|
|
|
@@ -537,7 +574,7 @@ export struct LocalMusic {
|
|
|
});
|
|
|
|
|
|
//侧滑广播接收时间
|
|
|
- let eventUpdateSwipeBack: emitter.InnerEvent = { eventId: 888 }
|
|
|
+ let eventUpdateSwipeBack: emitter.InnerEvent = { eventId: EventConstants.EVENT_SWIPE_BACK_UPDATE }
|
|
|
// 监听广播事件(打开其他应用处理)
|
|
|
emitter.on(eventUpdateSwipeBack, (eventData: emitter.EventData) => {
|
|
|
|
|
|
@@ -548,13 +585,50 @@ export struct LocalMusic {
|
|
|
});
|
|
|
|
|
|
//ScanFilePage广播接收时间
|
|
|
- let eventScanUpdate: emitter.InnerEvent = { eventId: 101 }
|
|
|
+ let eventScanUpdate: emitter.InnerEvent = { eventId: EventConstants.EVENT_SCAN_UPDATE }
|
|
|
// 监听ScanFilePage广播事件(更新数据库)
|
|
|
emitter.on(eventScanUpdate, (eventData: emitter.EventData) => {
|
|
|
this.doUpdateData()
|
|
|
});
|
|
|
|
|
|
- let eventSetting: emitter.InnerEvent = { eventId: 333 }
|
|
|
+ // 监听歌单播放请求事件
|
|
|
+ let eventPlaylistPlay: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYLIST_PLAY }
|
|
|
+ emitter.on(eventPlaylistPlay, (eventData: emitter.EventData) => {
|
|
|
+ Logger.info('heanup eventPlaylistPlay received - full eventData: ' + JSON.stringify(eventData))
|
|
|
+ Logger.info('heanup eventPlaylistPlay received - eventData.data: ' + JSON.stringify(eventData.data))
|
|
|
+
|
|
|
+ const data = eventData.data as Record<string, Object>
|
|
|
+
|
|
|
+ if (!data) {
|
|
|
+ Logger.error('heanup eventPlaylistPlay: eventData.data is undefined or null')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查歌单播放数据结构
|
|
|
+ if (data.playlistId && data.songFilePaths && data.startIndex !== undefined) {
|
|
|
+ Logger.info('heanup eventPlaylistPlay: 接收到歌单播放数据')
|
|
|
+ // 手动构建数据对象以避免类型转换问题
|
|
|
+ const playlistData: PlaylistEventData = {
|
|
|
+ playlistId: data.playlistId as string,
|
|
|
+ playlistName: data.playlistName as string,
|
|
|
+ songCount: data.songCount as number,
|
|
|
+ startIndex: data.startIndex as number,
|
|
|
+ songFilePaths: data.songFilePaths as string[]
|
|
|
+ }
|
|
|
+ // 根据文件路径重新构建歌曲列表
|
|
|
+ this.handlePlaylistPlayRequest(
|
|
|
+ playlistData.playlistId,
|
|
|
+ playlistData.playlistName,
|
|
|
+ playlistData.songFilePaths,
|
|
|
+ playlistData.startIndex
|
|
|
+ )
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ Logger.error('heanup eventPlaylistPlay: 接收到无效的数据结构')
|
|
|
+ });
|
|
|
+
|
|
|
+ let eventSetting: emitter.InnerEvent = { eventId: EventConstants.EVENT_SETTING_UPDATE }
|
|
|
// 监听广播事件(通用设置配置更新)
|
|
|
emitter.on(eventSetting, (eventData: emitter.EventData) => {
|
|
|
this.doChangeSetting()
|
|
|
@@ -704,7 +778,6 @@ export struct LocalMusic {
|
|
|
const context = getContext(this) as common.UIAbilityContext
|
|
|
context.getApplicationContext().setColorMode(colorMode)
|
|
|
}
|
|
|
-
|
|
|
initSetting() {
|
|
|
this.sortType = PreferencesUtil.getNumberSync(SettingPage.SORT_TYPE, 4)
|
|
|
this.isCustomizeBg = PreferencesUtil.getBooleanSync(SettingPage.IS_CUSTOMIZE_BG, false)
|
|
|
@@ -794,7 +867,6 @@ export struct LocalMusic {
|
|
|
this.setBarHeightNormal()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
onPageShow() {
|
|
|
this.knockController?.immersiveListening();
|
|
|
app.setImageCacheCount(100);
|
|
|
@@ -802,7 +874,6 @@ export struct LocalMusic {
|
|
|
app.setImageRawDataCacheSize(104857600);
|
|
|
Logger.info('onecold onPageShow currentBreakpoint= ' + this.currentBreakpoint)
|
|
|
}
|
|
|
-
|
|
|
//开启线程查看各个数据库
|
|
|
makeWorker() {
|
|
|
setTimeout(() => {
|
|
|
@@ -837,7 +908,6 @@ export struct LocalMusic {
|
|
|
this.doUpdateData()
|
|
|
break;
|
|
|
case 102: //查询媒体库列表
|
|
|
- this.isRefreshing = false
|
|
|
this.mediaKuList = e.data.data
|
|
|
Logger.info('onecold 查询媒体库列表 this.mediaKuList length= ' + this.mediaKuList.length)
|
|
|
Utility.doSortListAscending(this.mediaKuList)
|
|
|
@@ -856,7 +926,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
break;
|
|
|
case 103: //收到查询艺术家列表
|
|
|
- this.isRefreshing = false
|
|
|
this.artistMap = e.data.data1;
|
|
|
this.artistList = e.data.data2;
|
|
|
PreferencesUtil.putSync('artistCount', this.artistList.length)
|
|
|
@@ -869,17 +938,15 @@ export struct LocalMusic {
|
|
|
} else {
|
|
|
PreferencesUtil.putSync('artistList', JSON.stringify(this.artistList));
|
|
|
}
|
|
|
- // 处理并缓存前80条艺术家数据
|
|
|
+ // 处理并缓存前60条艺术家数据
|
|
|
const sortedEntries = Array.from(this.artistMap.entries())
|
|
|
.sort((a, b) => b[1].length - a[1].length)
|
|
|
- .slice(0, 80);
|
|
|
+ .slice(0, 60);
|
|
|
|
|
|
PreferencesUtil.putSync('artistMap', JSON.stringify(sortedEntries));
|
|
|
-
|
|
|
break;
|
|
|
|
|
|
case 104: //收到查询专辑列表
|
|
|
- this.isRefreshing = false
|
|
|
this.albumMap = e.data.data1;
|
|
|
|
|
|
this.albumList = e.data.data2
|
|
|
@@ -900,7 +967,7 @@ export struct LocalMusic {
|
|
|
}
|
|
|
const mapArrayAlbum = Array.from(this.albumMap.entries())
|
|
|
.sort((a, b) => b[1].length - a[1].length)
|
|
|
- .slice(0, 80);
|
|
|
+ .slice(0, 60);
|
|
|
PreferencesUtil.putSync('albumMap', JSON.stringify(mapArrayAlbum));
|
|
|
break;
|
|
|
|
|
|
@@ -1023,10 +1090,10 @@ export struct LocalMusic {
|
|
|
console.info('LifeCycleComponent aboutToDisappear');
|
|
|
this.knockController?.immersiveDisableListening();
|
|
|
this.curIndex = 0
|
|
|
- emitter.off(2);
|
|
|
- emitter.off(101);
|
|
|
- emitter.off(888);
|
|
|
- emitter.off(333);
|
|
|
+ emitter.off(EventConstants.EVENT_AUDIO_OPEN);
|
|
|
+ emitter.off(EventConstants.EVENT_SCAN_UPDATE);
|
|
|
+ emitter.off(EventConstants.EVENT_SWIPE_BACK_UPDATE);
|
|
|
+ emitter.off(EventConstants.EVENT_SETTING_UPDATE);
|
|
|
this.mDestroyPage = true;
|
|
|
this.mIjkMediaPlayer.setScreenOnWhilePlaying(false);
|
|
|
if (this.CONTROL_PlayStatus != PlayStatus.INIT) {
|
|
|
@@ -1321,7 +1388,7 @@ export struct LocalMusic {
|
|
|
this.titleBarModel.setTitleName(Utility.resourceToString(this.context, $r('app.string.album')))
|
|
|
break
|
|
|
case 4: //同步数据
|
|
|
- this.asyncCurrentPathData()
|
|
|
+ // this.asyncCurrentPathData()
|
|
|
break
|
|
|
}
|
|
|
|
|
|
@@ -1458,7 +1525,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
doSortType(index: number) {
|
|
|
switch (index) {
|
|
|
case 0:
|
|
|
@@ -1600,7 +1666,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
//拉起音频
|
|
|
goSelectMusic() {
|
|
|
if (DeviceUtil.getDeviceType() == resourceManager.DeviceType.DEVICE_TYPE_TABLET ||
|
|
|
@@ -1935,7 +2000,6 @@ export struct LocalMusic {
|
|
|
if (!newPath.includes(this.lockPath)) { //如果移动到私密,就不插入数据库
|
|
|
this.table.insert(newItem, (id: number) => {
|
|
|
//加入数据库
|
|
|
-
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -2099,7 +2163,6 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
|
}
|
|
|
-
|
|
|
build() {
|
|
|
|
|
|
Scroll() {
|
|
|
@@ -2205,22 +2268,7 @@ export struct LocalMusic {
|
|
|
if(this.isGridMusic){
|
|
|
this.getGridView()
|
|
|
}else {
|
|
|
- Refresh({ refreshing: $$this.isRefreshing, refreshingContent: this.contentNode }) {
|
|
|
- this.getListView()
|
|
|
- }
|
|
|
- .pullDownRatio(this.ratioL)
|
|
|
- .pullToRefresh(true)
|
|
|
- .refreshOffset(0)
|
|
|
- .onOffsetChange((offset: number) => {
|
|
|
- // 越接近最大距离,下拉跟手系数越小。
|
|
|
- this.ratioL = 1 - Math.pow((offset / this.maxRefreshingHeight), 3);
|
|
|
- })
|
|
|
- .onStateChange((refreshStatus: RefreshStatus) => {
|
|
|
- console.info('onecold Refresh onStatueChange state is ' + refreshStatus);
|
|
|
- })
|
|
|
- .onRefreshing(async () => {
|
|
|
- this.refreshCurrent()
|
|
|
- })
|
|
|
+ this.getListView()
|
|
|
}
|
|
|
}
|
|
|
if (this.modeType == 0) {
|
|
|
@@ -2403,7 +2451,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-
|
|
|
@Builder
|
|
|
TagsContentCoverBuilder() {
|
|
|
Scroll() {
|
|
|
@@ -2595,6 +2642,61 @@ export struct LocalMusic {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 加载所有歌单
|
|
|
+ */
|
|
|
+ async loadAllPlaylists() {
|
|
|
+ try {
|
|
|
+ this.allPlaylists = await this.playlistTable?.queryAllPlaylists()!
|
|
|
+ LogUtil.info('heanup Loaded playlists: ' + this.allPlaylists.length)
|
|
|
+ } catch (error) {
|
|
|
+ LogUtil.error('heaunp Failed to load playlists: ' + error.message)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 显示添加到歌单对话框
|
|
|
+ */
|
|
|
+ async showAddToPlaylistDialog(item: VideoItem) {
|
|
|
+ // 加载最新的歌单列表
|
|
|
+ await this.loadAllPlaylists()
|
|
|
+
|
|
|
+ showAddToPlaylistDialog(
|
|
|
+ item,
|
|
|
+ this.allPlaylists,
|
|
|
+ async (playlistId: string) => {
|
|
|
+ // 添加歌曲到歌单
|
|
|
+ const success = await this.playlistTable?.addSongToPlaylist(playlistId, item.filePath)
|
|
|
+ if (success) {
|
|
|
+ ToastUtil.showToast('已添加到歌单')
|
|
|
+ // 重新加载歌单列表
|
|
|
+ await this.loadAllPlaylists()
|
|
|
+ } else {
|
|
|
+ ToastUtil.showToast('歌曲已在该歌单中')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ () => {
|
|
|
+ LogUtil.info('取消添加到歌单')
|
|
|
+ },
|
|
|
+ () => {
|
|
|
+ // 创建新歌单
|
|
|
+ showCreatePlaylistDialog(
|
|
|
+ async (name: string, description: string) => {
|
|
|
+ const success = await this.playlistTable?.createPlaylist(name, description)
|
|
|
+ if (success) {
|
|
|
+ ToastUtil.showToast('歌单创建成功')
|
|
|
+ // 重新加载歌单列表并打开添加对话框
|
|
|
+ await this.loadAllPlaylists()
|
|
|
+ await this.showAddToPlaylistDialog(item)
|
|
|
+ } else {
|
|
|
+ ToastUtil.showToast('歌单创建失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
doFav(item: VideoItem) {
|
|
|
LogUtil.info('onecold doFav isFav=' + item.isFav)
|
|
|
|
|
|
@@ -2781,9 +2883,7 @@ export struct LocalMusic {
|
|
|
}
|
|
|
return true
|
|
|
}
|
|
|
-
|
|
|
@State opacityItem: number = 1; // 控制透明度的状态变量
|
|
|
-
|
|
|
@Builder
|
|
|
private MusicItem(item: VideoItem, index?: number) {
|
|
|
Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
@@ -2981,7 +3081,7 @@ export struct LocalMusic {
|
|
|
|
|
|
private readonly tabs: string[] = ['文件夹', '媒体库', '艺术家', '专辑']
|
|
|
@State tabOptions: SegmentButtonOptions = SegmentButtonOptions.tab({
|
|
|
- buttons: [{ text: '文件夹' }, { text: '媒体库' },{ text: '艺术家' },{ text: '专辑' }],
|
|
|
+ buttons: [{ text: '文件夹' }, { text: '媒体库' },{ text: '艺术家' }],
|
|
|
direction: Direction.Ltr,
|
|
|
buttonPadding:{top:12,bottom:12},
|
|
|
backgroundColor: Color.Transparent,
|
|
|
@@ -3106,7 +3206,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
return (this.modeType == 2 || this.modeType == 3) && this.isCanBack
|
|
|
}
|
|
|
-
|
|
|
@Builder
|
|
|
coverHeader() {
|
|
|
if (this.isShowCoverHeader()) {
|
|
|
@@ -3265,20 +3364,6 @@ export struct LocalMusic {
|
|
|
|
|
|
return this.currentTitleCover
|
|
|
}
|
|
|
-
|
|
|
- refreshCurrent() {
|
|
|
- if(this.modeType==0){
|
|
|
- this.getHistoryList(false)
|
|
|
- this.asyncCurrentPathOnlyFile()
|
|
|
- }else if(this.modeType == 1){
|
|
|
- workerInstance.postMessage({ code: 2, data: this.context,data2:this.packName });
|
|
|
- }else if(this.modeType == 2){
|
|
|
- workerInstance.postMessage({ code: 3, data: this.context });
|
|
|
- }else if(this.modeType == 3){
|
|
|
- workerInstance.postMessage({ code: 4, data: this.context });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
@Builder
|
|
|
listViewTitle() {
|
|
|
Column() {
|
|
|
@@ -3494,18 +3579,26 @@ export struct LocalMusic {
|
|
|
this.isSearchMode = true
|
|
|
})
|
|
|
|
|
|
- // Image($r("app.media.refresh"))
|
|
|
- // .fillColor(this.themeColor)
|
|
|
- // .width(25)
|
|
|
- // .visibility(this.isHistory || this.isCanBack || this.isSearchMode ? Visibility.None : Visibility.Visible)
|
|
|
- // .animation({
|
|
|
- // duration: 666,
|
|
|
- // curve: 'ease-in-out' // 可选动画曲线
|
|
|
- // })
|
|
|
- // .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
|
|
|
- // .onClick(() => {
|
|
|
- // this.refreshCurrent()
|
|
|
- // })
|
|
|
+ Image($r("app.media.refresh"))
|
|
|
+ .fillColor(this.themeColor)
|
|
|
+ .width(25)
|
|
|
+ .visibility(this.isHistory || this.isCanBack || this.isSearchMode ? Visibility.None : Visibility.Visible)
|
|
|
+ .animation({
|
|
|
+ duration: 666,
|
|
|
+ curve: 'ease-in-out' // 可选动画曲线
|
|
|
+ })
|
|
|
+ .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
|
|
|
+ .onClick(() => {
|
|
|
+ if (this.isFavMusic) {
|
|
|
+ this.getFavList(true)
|
|
|
+ } else {
|
|
|
+ if(this.modeType == 0){
|
|
|
+ this.asyncCurrentPathData()
|
|
|
+ }else if(this.modeType ==1){
|
|
|
+ workerInstance.postMessage({ code: 2, data: this.context,data2:this.packName });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
Image($r("app.media.top_rank"))
|
|
|
.width(25)
|
|
|
@@ -3731,7 +3824,7 @@ export struct LocalMusic {
|
|
|
})
|
|
|
.transition(TransitionEffect.scale({ x: 0.8, y: 0.8 }).animation({ duration: 500 }))
|
|
|
.transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 0.8, y: 0.8 }).animation({ duration: 500 }),
|
|
|
- TransitionEffect.scale({ x: 0, y: 0 }) ))
|
|
|
+ TransitionEffect.scale({ x: 0, y: 0 })))
|
|
|
.gesture(
|
|
|
GestureGroup(GestureMode.Exclusive,
|
|
|
SwipeGesture({ direction: SwipeDirection.Horizontal })
|
|
|
@@ -3903,7 +3996,6 @@ export struct LocalMusic {
|
|
|
.scrollBar(BarState.Off)
|
|
|
|
|
|
}
|
|
|
-
|
|
|
//瀑布流卡片布局
|
|
|
@Builder
|
|
|
private MusicWaterCardItem(item: VideoItem, index: number) {
|
|
|
@@ -4070,8 +4162,6 @@ export struct LocalMusic {
|
|
|
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
// Grid布局的开始
|
|
|
private dragRefOffSetX: number = 0;
|
|
|
private dragRefOffSetY: number = 0;
|
|
|
@@ -4090,16 +4180,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // [Start itemMove_start]
|
|
|
- // itemMoveGrid(index: number, newIndex: number): void {
|
|
|
- // if (!this.isDraggable(newIndex)) {
|
|
|
- // return;
|
|
|
- // }
|
|
|
- // let tmp = this.videoLocalList.splice(index, 1);
|
|
|
- // this.videoLocalList.splice(newIndex, 0, tmp[0]);
|
|
|
- // // this.bigItemIndex = this.videoLocalList.findIndex((item) => item === 0);
|
|
|
- // }
|
|
|
-
|
|
|
isInLeft(index: number) {
|
|
|
return index % 2 == 0;
|
|
|
}
|
|
|
@@ -4196,7 +4276,6 @@ export struct LocalMusic {
|
|
|
.scale({ x: this.scaleItem === index ? 1.02 : 1, y: this.scaleItem === index ? 1.02 : 1 })
|
|
|
.zIndex(this.dragItem === index ? 1 : 0)
|
|
|
.translate(this.dragItem === index ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 })
|
|
|
- // .hitTestBehavior(this.isDraggable(this.videoLocalList.indexOf(item)) ? HitTestMode.Default : HitTestMode.None)
|
|
|
|
|
|
|
|
|
}, (item: VideoItem) => item.filePath)
|
|
|
@@ -4217,7 +4296,6 @@ export struct LocalMusic {
|
|
|
.scrollBar(BarState.Off)
|
|
|
.supportAnimation(true)
|
|
|
.cachedCount(this.twoFingerType==1?5:this.twoFingerType==2?4:3)
|
|
|
- // .columnsTemplate('1fr '.repeat(this.currentWidthBreakpoint === WidthBreakpoint.WIDTH_SM ? 2 : 5))
|
|
|
.columnsTemplate(
|
|
|
this.twoFingerType == 3 ? 'repeat(auto-fit, 160)' :
|
|
|
this.twoFingerType == 2 ? 'repeat(auto-fit, 110)' : 'repeat(auto-fit, 80)'
|
|
|
@@ -4236,16 +4314,11 @@ export struct LocalMusic {
|
|
|
|
|
|
}))
|
|
|
.enableScrollInteraction(true)
|
|
|
- // 滚轴滑动,记录下滑动时的起始位置和终点位置
|
|
|
.onScrollIndex((start: number, end: number) => {
|
|
|
this.startIndex = start
|
|
|
this.endIndex = end
|
|
|
})
|
|
|
.onScrollFrameBegin((offset: number) => {
|
|
|
- //滚动小屏幕 比如puraX外屏和手机横屏可以隐藏bottomBarHeight topBarHeight
|
|
|
- // if (this.isPhoneLan()) {
|
|
|
- // this.setBarHeightHide(offset)
|
|
|
- // } else
|
|
|
if (this.currentWidthBreakpoint !== WidthBreakpoint.WIDTH_SM ||
|
|
|
(this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_MD &&
|
|
|
this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_SM)) {
|
|
|
@@ -4260,7 +4333,6 @@ export struct LocalMusic {
|
|
|
|
|
|
return { offsetRemain: offset };
|
|
|
})
|
|
|
- //允许拖拽音乐和视频到List或Grid上自动导入视频
|
|
|
.allowDrop([uniformTypeDescriptor.UniformDataType.AUDIO,uniformTypeDescriptor.UniformDataType.VIDEO])
|
|
|
.onDrop((event?: DragEvent) => {
|
|
|
try {
|
|
|
@@ -4358,8 +4430,6 @@ export struct LocalMusic {
|
|
|
})
|
|
|
.draggable(false)
|
|
|
.opacity(this.opacityItem)// 绑定透明度
|
|
|
- // .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
|
|
|
- // .animation({ duration: 500, curve: Curve.Ease }))
|
|
|
.animation({
|
|
|
duration: 666,
|
|
|
curve: 'ease-in-out' // 可选动画曲线
|
|
|
@@ -4537,8 +4607,6 @@ export struct LocalMusic {
|
|
|
return wightG
|
|
|
}
|
|
|
@State isShowDetail:boolean = false
|
|
|
- // @State isShowDetailGrid:boolean = false
|
|
|
- // @State isShowEditGrid:boolean = false
|
|
|
@State longItemFilePathDetail:string =''
|
|
|
@Builder
|
|
|
MenuBuilder(item: VideoItem, index: number, filePath: string) {
|
|
|
@@ -4578,6 +4646,16 @@ export struct LocalMusic {
|
|
|
this.longItemFilePath = ''
|
|
|
})
|
|
|
|
|
|
+ MenuItem({
|
|
|
+ symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.music_note_list')),
|
|
|
+ content: '添加到歌单'
|
|
|
+ })
|
|
|
+ .visibility(item.type === CommonConstants.TYPE_IS_DIR ? Visibility.None : Visibility.Visible)
|
|
|
+ .onClick(async () => {
|
|
|
+ this.longItemFilePath = ''
|
|
|
+ await this.showAddToPlaylistDialog(item)
|
|
|
+ })
|
|
|
+
|
|
|
MenuItem({
|
|
|
symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.square_and_pencil')),
|
|
|
content: '编辑标签'
|
|
|
@@ -4593,7 +4671,6 @@ export struct LocalMusic {
|
|
|
.onClick(async() => {
|
|
|
this.setEditStrEmpty()
|
|
|
this.tempLyricContent = await this.getLyricContent(item);
|
|
|
- // console.info('onecold 长按this.tempLyricContent' +this.tempLyricContent)
|
|
|
if(this.isGridMusic||this.twoFingerType==4){
|
|
|
this.longItemFilePath = item.filePath
|
|
|
}else{
|
|
|
@@ -4678,7 +4755,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-
|
|
|
private listMaxScrollOffsetY: number = 0
|
|
|
@State selectedIndex: number = -1
|
|
|
|
|
|
@@ -4706,25 +4782,6 @@ export struct LocalMusic {
|
|
|
this.pinchValue = 1;
|
|
|
this.scaleValue = 1;
|
|
|
}
|
|
|
-
|
|
|
- // 扫描当前目录下的文件,不扫描子目录
|
|
|
- asyncCurrentPathOnlyFile(){
|
|
|
- if(this.modeType==0){
|
|
|
- const task = new taskpool.Task(scanCurrentDirectoryTask, getContext(this), this.currentPath,
|
|
|
- this.lockPath,PreferencesUtil.getStringSync('COVER_API',''));
|
|
|
- taskpool.execute(task, taskpool.Priority.HIGH).then(()=>{
|
|
|
- if(this.modeType==0){
|
|
|
- this.getSortedFiles(this.currentPath)
|
|
|
- }
|
|
|
- setTimeout(() => {
|
|
|
- this.isRefreshing = false;
|
|
|
- }, 100)
|
|
|
- }).catch((e:object)=>{
|
|
|
- console.info("task1 catch e: " + e);
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
@Builder
|
|
|
getListView() {
|
|
|
|
|
|
@@ -5078,6 +5135,7 @@ export struct LocalMusic {
|
|
|
}
|
|
|
|
|
|
private async doPlay(item: VideoItem, index?: number, isFromSonPlayList?: boolean,isOpen?:boolean) {
|
|
|
+ Logger.info(`heanup doPlay被调用 - 歌曲: ${item.name}, 文件路径: ${item.filePath}, 索引: ${index}, 类型: ${item.type}, isFromSonPlayList: ${isFromSonPlayList}`)
|
|
|
|
|
|
switch (item.type) {
|
|
|
case CommonConstants.TYPE_IS_DIR:
|
|
|
@@ -5307,6 +5365,8 @@ export struct LocalMusic {
|
|
|
if (index !== undefined) {
|
|
|
this.curIndex = index
|
|
|
}
|
|
|
+ // 确保播放列表是完整的歌单歌曲列表(已在finishLoadingPlaylist中设置)
|
|
|
+ Logger.info(`heanup isFromSonPlayList分支 - 当前播放列表长度: ${this.songList.length}, 当前索引: ${this.curIndex}`)
|
|
|
}else {
|
|
|
let globalVideoList = Utility.getGlobalList(this.videoLocalList, CommonConstants.TYPE_LOCAL) as VideoItem[];
|
|
|
this.curIndex = Utility.getCurIndexFromGlobalList(globalVideoList, item.filePath)
|
|
|
@@ -5503,7 +5563,6 @@ export struct LocalMusic {
|
|
|
this.showPlayerView()
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
//打开播放页
|
|
|
showPlayerView() {
|
|
|
|
|
|
@@ -5518,8 +5577,6 @@ export struct LocalMusic {
|
|
|
ToastUtil.showToast('当前播放列表为空,请先导入音乐。');
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
@Builder
|
|
|
playConRigth() {
|
|
|
Row() {
|
|
|
@@ -5688,15 +5745,6 @@ export struct LocalMusic {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- // let doChangeLyric = false
|
|
|
- // if(item.filePath==this.currentSong?.filePath){
|
|
|
- // if(this.lyricConStr !== this.lyricContent){
|
|
|
- // doChangeLyric = true
|
|
|
- // }
|
|
|
- // }else if(this.lyricConStr !== this.tempLyricContent){
|
|
|
- // doChangeLyric = true
|
|
|
- // }
|
|
|
-
|
|
|
//用户更改了封面,那就内嵌下封面
|
|
|
if(StrUtil.isNotEmpty(this.imagePathStr)){
|
|
|
const resultCover:boolean = await changeMusicCover(this.context,
|
|
|
@@ -5712,8 +5760,6 @@ export struct LocalMusic {
|
|
|
title: this.titleStr,
|
|
|
artist: this.artistStr,
|
|
|
album: this.ablumStr,
|
|
|
- // LYRICS:this.lyricConStr,
|
|
|
- // USLT:this.lyricConStr,
|
|
|
TYER:this.yearStr,
|
|
|
genre:this.genreStr,
|
|
|
track:this.trackStr,
|
|
|
@@ -5723,7 +5769,6 @@ export struct LocalMusic {
|
|
|
lyricist:this.lyricistStr,
|
|
|
TEXT:this.lyricistStr,//ID3v2 使用 TEXT 字段来表示作词者
|
|
|
comment:this.commentStr,
|
|
|
- // comm:this.commentStr,//ID3v2:使用 COMM(Comment)字段。
|
|
|
disc:this.discStr,
|
|
|
};
|
|
|
|
|
|
@@ -6336,7 +6381,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
.margin({ bottom: 20 })
|
|
|
}
|
|
|
-
|
|
|
setEditStrEmpty(){
|
|
|
this.imagePathStr = ''
|
|
|
this.lyricConStr = ''
|
|
|
@@ -6363,7 +6407,6 @@ export struct LocalMusic {
|
|
|
.width('100%')
|
|
|
.height('100%')
|
|
|
}
|
|
|
-
|
|
|
@Builder
|
|
|
songDetail(currentItem:VideoItem) {
|
|
|
Column() {
|
|
|
@@ -7106,7 +7149,6 @@ export struct LocalMusic {
|
|
|
this.sonDataSource.pushArrayData(this.songList)
|
|
|
this.curIndex = Utility.getIndexFromList(this.songList, this.videoUrl)
|
|
|
}
|
|
|
-
|
|
|
@Builder
|
|
|
PlayList() {
|
|
|
List({ scroller: this.playListScroller }) {
|
|
|
@@ -7824,7 +7866,6 @@ export struct LocalMusic {
|
|
|
private castSeek: boolean = false;
|
|
|
private castItem: avSession.AVQueueItem | undefined = undefined;
|
|
|
// @State isBgPlayOpen:boolean = true //是否启用后台播放
|
|
|
-
|
|
|
@State imageLabel: PixelMap | Resource = CommonConstants.musicBgList[0];
|
|
|
@State imageLabelBg: PixelMap | Resource = CommonConstants.musicBgList[0];
|
|
|
@State rotateAngle2: number = -9
|
|
|
@@ -7843,7 +7884,6 @@ export struct LocalMusic {
|
|
|
@State lyricContent: string = ''
|
|
|
@State isDebug: boolean = false
|
|
|
@State isHightLightCenter: boolean = true
|
|
|
-
|
|
|
/**
|
|
|
* 初始化歌词加载与展示逻辑
|
|
|
* @param lyricPath 歌词文件路径(支持普通.lrc和加密.lrcc)
|
|
|
@@ -8568,7 +8608,6 @@ export struct LocalMusic {
|
|
|
.position({ bottom: this.isHiCarSmall()?50:(this.isCoverOpacity() ? 55 : 70) }) // 将 固定在底部
|
|
|
|
|
|
}
|
|
|
-
|
|
|
//播放控制上一首 下一首 暂停和播放
|
|
|
@Builder
|
|
|
playCenterView(){
|
|
|
@@ -9367,10 +9406,8 @@ export struct LocalMusic {
|
|
|
}
|
|
|
.width('66%')
|
|
|
}
|
|
|
-
|
|
|
@State isOpenPip: boolean = false
|
|
|
@State pipBgIndex: number = 0
|
|
|
-
|
|
|
// 构建字号控制器
|
|
|
@Builder
|
|
|
BuildFontControls(isPip: boolean) {
|
|
|
@@ -10162,7 +10199,6 @@ export struct LocalMusic {
|
|
|
? '歌词时间已重置'
|
|
|
: `歌词已${this.timeOffset < 0 ? '延后' : '提前'} ${absValue.toFixed(1)} 秒`
|
|
|
}
|
|
|
-
|
|
|
// 导入 本地歌词 搜索歌词
|
|
|
@Builder
|
|
|
pushLyricButton(icon: Resource, step: number, label: string) {
|
|
|
@@ -10770,8 +10806,8 @@ export struct LocalMusic {
|
|
|
this.isShowMoreView = false
|
|
|
break;
|
|
|
case 20://AB循环
|
|
|
- this.isABSheet = !this.isABSheet;
|
|
|
- this.isShowMoreView = false
|
|
|
+ this.isOpenAB = !this.isOpenAB;
|
|
|
+ this.isABSheet = false
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
@@ -10798,8 +10834,8 @@ export struct LocalMusic {
|
|
|
onClickBItem: async ()=>{
|
|
|
if(this.mIjkMediaPlayer){
|
|
|
this.jumpBTime = await this.mIjkMediaPlayer.getCurrentPosition()
|
|
|
- if(this.jumpBTime<=this.jumpATime||stringForTime(this.jumpATime)==stringForTime(this.jumpBTime)){
|
|
|
- ToastUtil.showToast('设置B点时间不能小于或等于A点时间')
|
|
|
+ if(this.jumpBTime<=this.jumpATime){
|
|
|
+ ToastUtil.showToast('设置B点时间不能小于A点时间')
|
|
|
this.jumpBTime = 0
|
|
|
}
|
|
|
}
|
|
|
@@ -10939,7 +10975,6 @@ export struct LocalMusic {
|
|
|
}
|
|
|
Logger.info(`[${TAG}] onecold onStateChange: ${this.curState}, reason: ${reason}`);
|
|
|
}
|
|
|
-
|
|
|
onActionEvent(event: PiPWindow.PiPActionEventType, status: number | undefined) {
|
|
|
LogUtil.info('onecold onActionEvent = ' + event + ' status=' + status)
|
|
|
switch (event) {
|
|
|
@@ -10970,7 +11005,6 @@ export struct LocalMusic {
|
|
|
this.buttonAction = event + `-status:${status}`;
|
|
|
Logger.info(`[${TAG}] onActionEvent: ${this.buttonAction} status:${status}}`);
|
|
|
}
|
|
|
-
|
|
|
/**
|
|
|
* 画中画功能(悬浮歌词功能)结束
|
|
|
*
|
|
|
@@ -11472,7 +11506,6 @@ export struct LocalMusic {
|
|
|
this.loadingVisible = Visibility.None;
|
|
|
this.replayVisible = Visibility.Visible;
|
|
|
}
|
|
|
-
|
|
|
private async play(url: string,startOffset?:number) {
|
|
|
let that = this;
|
|
|
that.showLoadIng();
|
|
|
@@ -12040,6 +12073,23 @@ export struct LocalMusic {
|
|
|
|
|
|
public setIsPlaying(isPlayer: boolean) {
|
|
|
this.isPlaying = isPlayer;
|
|
|
+
|
|
|
+ // 发送播放状态变化事件给歌单详情页面
|
|
|
+ try {
|
|
|
+ const eventPlaybackStatus: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYBACK_STATUS }
|
|
|
+ const currentFilePath = this.currentSong?.filePath || ''
|
|
|
+ const eventData: emitter.EventData = {
|
|
|
+ data: {
|
|
|
+ isPlaying: this.isPlaying,
|
|
|
+ curIndex: this.curIndex,
|
|
|
+ currentFilePath: currentFilePath
|
|
|
+ }
|
|
|
+ };
|
|
|
+ emitter.emit(eventPlaybackStatus, eventData)
|
|
|
+ Logger.info(`heanup 发送播放状态变化事件: isPlaying=${this.isPlaying}, curIndex=${this.curIndex}, currentFilePath=${currentFilePath}`)
|
|
|
+ } catch (error) {
|
|
|
+ Logger.error('heanup 发送播放状态变化事件失败: ' + error)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private setPlaybackStateChangeListener(): void {
|
|
|
@@ -12245,7 +12295,6 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
|
};
|
|
|
-
|
|
|
/**
|
|
|
* Gesture method onActionUpdate.
|
|
|
*
|
|
|
@@ -12275,7 +12324,6 @@ export struct LocalMusic {
|
|
|
this.currentTime = this.stringForTime(position);
|
|
|
this.isCurrentTime = false
|
|
|
}
|
|
|
-
|
|
|
private sessionRewindCallback = (time?: number) => {
|
|
|
if (!time) {
|
|
|
return;
|
|
|
@@ -13019,9 +13067,114 @@ export struct LocalMusic {
|
|
|
* 穿山甲广告代码结束
|
|
|
*/
|
|
|
|
|
|
+ /**
|
|
|
+ * 处理歌单播放请求
|
|
|
+ */
|
|
|
+ private handlePlaylistPlayRequest(playlistId: string, playlistName: string, songFilePaths: string[], startIndex: number) {
|
|
|
+ try {
|
|
|
+ Logger.info(`heanup 处理歌单播放请求: ${playlistName}, 歌曲数量: ${songFilePaths.length}, 开始索引: ${startIndex}`)
|
|
|
+
|
|
|
+ // 从数据库重新加载这些歌曲,使用索引记录位置以保持顺序
|
|
|
+ const songMap: Map<number, VideoItem> = new Map()
|
|
|
+ let completedQueries = 0
|
|
|
|
|
|
-}
|
|
|
+ Logger.info(`heanup 开始从数据库查询 ${songFilePaths.length} 首歌曲`)
|
|
|
+
|
|
|
+ // 遍历所有文件路径,使用索引记录位置
|
|
|
+ for (let i = 0; i < songFilePaths.length; i++) {
|
|
|
+ const filePath = songFilePaths[i]
|
|
|
+ const index = i
|
|
|
+ Logger.info(`heanup 正在查询歌曲[${index}]: ${filePath}`)
|
|
|
+
|
|
|
+ // 使用已初始化的MediaTable实例从数据库查询歌曲信息
|
|
|
+ const queryPromise = this.table.queryVideoByFilePath(filePath)
|
|
|
+ Logger.info(`heanup 创建了查询Promise,开始等待结果[${index}]: ${filePath}`)
|
|
|
+
|
|
|
+ queryPromise.then((videoItem) => {
|
|
|
+ completedQueries++
|
|
|
+ Logger.info(`heanup 查询Promise返回结果[${index}]: ${filePath}, 找到歌曲: ${videoItem ? videoItem.name : 'null'}`)
|
|
|
+
|
|
|
+ if (videoItem) {
|
|
|
+ // 使用索引作为key保存到Map中,保持原始顺序
|
|
|
+ songMap.set(index, videoItem)
|
|
|
+ Logger.info(`heanup 从数据库找到歌曲[${index}]: ${videoItem.name} (${completedQueries}/${songFilePaths.length})`)
|
|
|
+ } else {
|
|
|
+ Logger.warn(`heanup 数据库中未找到歌曲[${index}]: ${filePath} (${completedQueries}/${songFilePaths.length})`)
|
|
|
+ }
|
|
|
|
|
|
+ // 检查是否所有歌曲都已加载完成
|
|
|
+ if (completedQueries === songFilePaths.length) {
|
|
|
+ Logger.info(`heanup 所有数据库查询完成,共找到 ${songMap.size} 首歌曲`)
|
|
|
+
|
|
|
+ // 按照索引顺序重建歌曲数组
|
|
|
+ const songs: VideoItem[] = []
|
|
|
+ for (let j = 0; j < songFilePaths.length; j++) {
|
|
|
+ const song = songMap.get(j)
|
|
|
+ if (song) {
|
|
|
+ songs.push(song)
|
|
|
+ Logger.info(`heanup 按顺序添加歌曲[${j}]: ${song.name}`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Logger.info(`heanup 最终歌曲列表顺序: ${songs.map((s, idx) => `[${idx}]${s.name}`).join(', ')}`)
|
|
|
+ this.finishLoadingPlaylist(songs, startIndex, playlistName)
|
|
|
+ }
|
|
|
+ }).catch((error: Error) => {
|
|
|
+ completedQueries++
|
|
|
+ Logger.error(`heanup 查询歌曲失败[${index}]: ${filePath}, 错误: ${error.message} (${completedQueries}/${songFilePaths.length})`)
|
|
|
+
|
|
|
+ // 即使出错也要检查是否完成所有查询
|
|
|
+ if (completedQueries === songFilePaths.length) {
|
|
|
+ Logger.info(`heanup 所有数据库查询完成(包含错误),共找到 ${songMap.size} 首歌曲`)
|
|
|
+
|
|
|
+ // 按照索引顺序重建歌曲数组
|
|
|
+ const songs: VideoItem[] = []
|
|
|
+ for (let j = 0; j < songFilePaths.length; j++) {
|
|
|
+ const song = songMap.get(j)
|
|
|
+ if (song) {
|
|
|
+ songs.push(song)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.finishLoadingPlaylist(songs, startIndex, playlistName)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ Logger.error('heanup 处理简化歌单播放请求失败: ' + error)
|
|
|
+ ToastUtil.showToast('播放失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 完成歌单加载并开始播放
|
|
|
+ */
|
|
|
+ private finishLoadingPlaylist(songs: VideoItem[], startIndex: number, playlistName: string) {
|
|
|
+ if (songs.length === 0) {
|
|
|
+ Logger.error('heanup 没有找到任何可播放的歌曲')
|
|
|
+ ToastUtil.showToast('没有找到可播放的歌曲')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.songList = songs
|
|
|
+
|
|
|
+ this.sonDataSource.pushArrayData(songs)
|
|
|
+
|
|
|
+ this.sonDataSource.notifyDataReload()
|
|
|
+
|
|
|
+ this.curIndex = startIndex
|
|
|
+
|
|
|
+ if (songs[startIndex]) {
|
|
|
+ // 确保当前播放的歌曲也更新到存储
|
|
|
+ AppStorage.setOrCreate('currentSong', songs[startIndex])
|
|
|
+ // 设置isFromSonPlayList=true,避免doPlay方法重新从全局列表构建播放列表
|
|
|
+ this.doPlay(songs[startIndex], startIndex, true)
|
|
|
+ }
|
|
|
+
|
|
|
+ PreferencesUtil.putSync('LastMusicList', this.songList)
|
|
|
+
|
|
|
+ ToastUtil.showToast(`开始播放歌单: ${playlistName}`)
|
|
|
+ }
|
|
|
+}
|
|
|
//视频气泡窗口的布局
|
|
|
@Builder
|
|
|
function customPopupBuilder(dataBu: BubbleBean) {
|
|
|
@@ -13172,51 +13325,4 @@ function getFileDirName(filePath: string,rootPath:string): string{
|
|
|
if(result.startsWith('.'))
|
|
|
result = result.replace(/\./g, '')
|
|
|
return result
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-//只扫描当前目录下文件(不扫描子文件夹)的方法
|
|
|
-@Concurrent
|
|
|
-async function scanCurrentDirectoryTask(context: Context, dirPath: string, lockPath: string, cover_api: string) {
|
|
|
- const table: MediaTable = new MediaTable(context);
|
|
|
-
|
|
|
- try {
|
|
|
- // 直接获取当前目录下的文件列表
|
|
|
- const files = FileUtil.listFileSync(dirPath);
|
|
|
-
|
|
|
- await Promise.all(files.map(async (file) => {
|
|
|
- const fPath = `${dirPath}/${file}`;
|
|
|
-
|
|
|
- // 跳过目录,只处理文件
|
|
|
- if (FileUtil.isDirectory(fPath)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 跳过特定格式文件
|
|
|
- if (fPath.endsWith('.lrc') || fPath.endsWith('.srt')) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查是否为媒体文件
|
|
|
- if (Utility.isMeidaByExtension(fPath)) {
|
|
|
- let mType = CommonConstants.TYPE_LOCAL;
|
|
|
- if (fPath.includes(lockPath)) {
|
|
|
- mType = CommonConstants.TYPE_LOCK;
|
|
|
- }
|
|
|
-
|
|
|
- const mediaItem = await Utility.uriGetMusicAssetsFromFile(
|
|
|
- context, fPath, mType, true
|
|
|
- );
|
|
|
-
|
|
|
- table.insert(mediaItem, (id: number) => {
|
|
|
- // 插入回调函数
|
|
|
- }, cover_api);
|
|
|
- }
|
|
|
- }));
|
|
|
- } catch (error) {
|
|
|
- console.error(' 扫描当前目录失败:', error);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+}
|