|
|
@@ -10,6 +10,7 @@ import {
|
|
|
DeviceUtil,
|
|
|
DisplayUtil,
|
|
|
FileUtil,
|
|
|
+ GlobalContext,
|
|
|
ImageUtil,
|
|
|
LogUtil,
|
|
|
MD5,
|
|
|
@@ -31,6 +32,7 @@ import { common, ConfigurationConstant } from '@kit.AbilityKit';
|
|
|
import { AnimationHelper, DialogAction, DialogHelper } from '@pura/harmony-dialog';
|
|
|
import { fileIo, fileUri, picker } from '@kit.CoreFileKit';
|
|
|
import { MessageEvents, util, worker, ErrorEvent } from '@kit.ArkTS';
|
|
|
+import Base64 from '@ohos.util';
|
|
|
import { Verify } from './Verify';
|
|
|
import { taskpool } from '@kit.ArkTS';
|
|
|
import { RotatingCover } from './RotatingCover';
|
|
|
@@ -92,6 +94,9 @@ import { showAddToPlaylistDialog } from '../dialog/AddToPlaylistDialog';
|
|
|
import { showCreatePlaylistDialog } from '../dialog/PlaylistDialog';
|
|
|
import { convertPlaylistSongsToVideoItems, emptyView } from '../pages/PlaylistDetailPage';
|
|
|
import { Playlist, PlaylistSong } from '../viewmodel/Playlist';
|
|
|
+import { Song } from '../viewmodel/Song';
|
|
|
+import { SongType } from '../common/enums/SongType';
|
|
|
+import { WebdavManager } from '../common/util/WebdavManager';
|
|
|
const TAG = 'LocalMusic';
|
|
|
|
|
|
/**
|
|
|
@@ -5503,6 +5508,54 @@ export struct LocalMusic {
|
|
|
this.startPlayOrResumePlay()
|
|
|
break;
|
|
|
|
|
|
+ case CommonConstants.TYPE_INTERNET:
|
|
|
+ // 处理网络音频播放(WebDAV)
|
|
|
+ Logger.info(`heanup 处理网络音频播放: ${item.name}, URL: ${item.filePath}`)
|
|
|
+
|
|
|
+ if (this.CONTROL_PlayStatus !== PlayStatus.INIT) {
|
|
|
+ this.stop();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isOpen) {
|
|
|
+ this.currentSong = item
|
|
|
+ if (index !== undefined) {
|
|
|
+ this.curIndex = index
|
|
|
+ }
|
|
|
+ this.songList = []
|
|
|
+ this.songList.push(item)
|
|
|
+ this.sonDataSource.pushArrayData(this.songList)
|
|
|
+ } else if (isFromSonPlayList) {
|
|
|
+ // 点击来自右下角的播放列表
|
|
|
+ this.currentSong = item
|
|
|
+ if (index !== undefined) {
|
|
|
+ this.curIndex = index
|
|
|
+ }
|
|
|
+ // 确保播放列表是完整的歌单歌曲列表(已在finishLoadingPlaylist中设置)
|
|
|
+ Logger.info(`heanup 网络音频 isFromSonPlayList分支 - 当前播放列表长度: ${this.songList.length}, 当前索引: ${this.curIndex}`)
|
|
|
+ } else {
|
|
|
+ // 从全局网络音频列表中查找
|
|
|
+ let globalVideoList = this.videoLocalList.filter(video => video.type === CommonConstants.TYPE_INTERNET) as VideoItem[];
|
|
|
+ this.curIndex = globalVideoList.findIndex(video => video.filePath === item.filePath);
|
|
|
+ if (this.curIndex === -1 && index !== undefined) {
|
|
|
+ this.curIndex = index;
|
|
|
+ }
|
|
|
+ this.songList = globalVideoList.length > 0 ? globalVideoList : [item];
|
|
|
+ this.currentSong = this.songList[this.curIndex];
|
|
|
+
|
|
|
+ this.sonDataSource.pushArrayData(this.songList)
|
|
|
+ }
|
|
|
+
|
|
|
+ AppStorage.setOrCreate('currentSong', this.currentSong);
|
|
|
+ this.videoUrl = this.currentSong.filePath // 网络URL
|
|
|
+ this.name = this.currentSong.name
|
|
|
+ this.cover = this.currentSong.pixelMapPath
|
|
|
+ this.artist = this.currentSong.artist
|
|
|
+
|
|
|
+ Logger.info(`heanup 准备播放网络音频 - 歌名: ${this.name}, 艺术家: ${this.artist}, URL: ${this.videoUrl}`)
|
|
|
+
|
|
|
+ this.startPlayOrResumePlay()
|
|
|
+ break;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -11481,6 +11534,12 @@ export struct LocalMusic {
|
|
|
}
|
|
|
|
|
|
updateLastPlayTimeStr(filePath: string) {
|
|
|
+ // 检查是否为网络音频(WebDAV),如果是则不更新本地数据库
|
|
|
+ if (this.currentSong && this.currentSong.type === CommonConstants.TYPE_INTERNET) {
|
|
|
+ Logger.info(`heanup 检测到网络音频播放,跳过数据库更新: ${filePath}`)
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
let lastPlayTime = DateUtil.getTodayStr('yyyy-MM-dd HH:mm:ss')
|
|
|
this.table.updateLastPlayedStrByFilePath(filePath, lastPlayTime, (success: boolean, error?: string) => {
|
|
|
if (success) {
|
|
|
@@ -11625,6 +11684,63 @@ export struct LocalMusic {
|
|
|
this.loadingVisible = Visibility.None;
|
|
|
this.replayVisible = Visibility.Visible;
|
|
|
}
|
|
|
+ /**
|
|
|
+ * 为WebDAV请求添加认证头
|
|
|
+ */
|
|
|
+ private addWebDavAuthHeader(headers: Map<string, string>, accountId: number): void {
|
|
|
+ try {
|
|
|
+ // 从WebDAV管理器获取账户信息
|
|
|
+ const webdavManager = WebdavManager.getInstance();
|
|
|
+ const accounts = webdavManager.getAllWebDavAccounts();
|
|
|
+ const account = accounts.find(acc => acc.id === accountId);
|
|
|
+
|
|
|
+ if (account && account.account && account.password) {
|
|
|
+ // 构建Basic认证头
|
|
|
+ const credentials = `${account.account}:${account.password}`;
|
|
|
+
|
|
|
+ // 简单的Base64编码实现
|
|
|
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
|
+ let encoded = '';
|
|
|
+ let i = 0;
|
|
|
+
|
|
|
+ while (i < credentials.length) {
|
|
|
+ const a = credentials.charCodeAt(i++);
|
|
|
+ const b = i < credentials.length ? credentials.charCodeAt(i++) : 0;
|
|
|
+ const c = i < credentials.length ? credentials.charCodeAt(i++) : 0;
|
|
|
+
|
|
|
+ const bitmap = (a << 16) | (b << 8) | c;
|
|
|
+
|
|
|
+ encoded += chars.charAt((bitmap >> 18) & 63);
|
|
|
+ encoded += chars.charAt((bitmap >> 12) & 63);
|
|
|
+ encoded += chars.charAt((bitmap >> 6) & 63);
|
|
|
+ encoded += chars.charAt(bitmap & 63);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理剩余字符
|
|
|
+ const remainder = credentials.length % 3;
|
|
|
+ if (remainder === 1) {
|
|
|
+ const bitmap = credentials.charCodeAt(credentials.length - 1) << 16;
|
|
|
+ encoded += chars.charAt((bitmap >> 18) & 63);
|
|
|
+ encoded += chars.charAt((bitmap >> 12) & 63);
|
|
|
+ encoded += '==';
|
|
|
+ } else if (remainder === 2) {
|
|
|
+ const bitmap = (credentials.charCodeAt(credentials.length - 2) << 16) | (credentials.charCodeAt(credentials.length - 1) << 8);
|
|
|
+ encoded += chars.charAt((bitmap >> 18) & 63);
|
|
|
+ encoded += chars.charAt((bitmap >> 12) & 63);
|
|
|
+ encoded += chars.charAt((bitmap >> 6) & 63);
|
|
|
+ encoded += '=';
|
|
|
+ }
|
|
|
+
|
|
|
+ headers.set("Authorization", `Basic ${encoded}`);
|
|
|
+ Logger.info(`heanup 为WebDAV添加Basic认证头,账户: ${account.account}`);
|
|
|
+ } else {
|
|
|
+ Logger.warn(`heanup 未找到WebDAV账户信息或账户缺少认证信息,accountId: ${accountId}`);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ Logger.error(`heanup 添加WebDAV认证头失败: ${error}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private async play(url: string,startOffset?:number) {
|
|
|
let that = this;
|
|
|
that.showLoadIng();
|
|
|
@@ -11659,6 +11775,28 @@ export struct LocalMusic {
|
|
|
["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
|
|
|
["referer", "https://www.bilibili.com"]
|
|
|
]);
|
|
|
+
|
|
|
+ // 如果是WebDAV网络音频,添加适当的HTTP头
|
|
|
+ if (this.currentSong && this.currentSong.type === CommonConstants.TYPE_INTERNET) {
|
|
|
+ const currentSong = this.currentSong;
|
|
|
+
|
|
|
+ // 安全地检查是否为WebDAV歌曲(通过检查URL格式)
|
|
|
+ const isWebDavSong = currentSong.filePath.startsWith('http://') ||
|
|
|
+ currentSong.filePath.startsWith('https://');
|
|
|
+
|
|
|
+ if (isWebDavSong) {
|
|
|
+ Logger.info(`heanup 检测到WebDAV播放,添加专用HTTP头`);
|
|
|
+
|
|
|
+ // 为WebDAV添加适当的请求头
|
|
|
+ headers.set("user_agent", "TTMusic-WebDAV/1.0");
|
|
|
+ headers.set("accept", "*/*");
|
|
|
+ headers.set("accept-range", "bytes");
|
|
|
+
|
|
|
+ // 注意:认证信息已经在URL中(在WebdavManager中处理),无需额外添加认证头
|
|
|
+ Logger.info(`heanup WebDAV认证信息已在URL中,跳过额外认证头设置`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
this.mIjkMediaPlayer.setDataSourceHeader(headers);
|
|
|
// if(PreferencesUtil.getBooleanSync(SettingPage.IS_MIDIACODEC_OPEN,false)){
|
|
|
// this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", "1"); // 启用硬件解码,会导致无法顺序播放
|
|
|
@@ -11960,7 +12098,11 @@ export struct LocalMusic {
|
|
|
LogUtils.getInstance().LOGI("OnErrorListener-->go:" + what + "===" + extra + " this.videoUrl=" + this.videoUrl)
|
|
|
that.hideLoadIng();
|
|
|
|
|
|
- if (StrUtil.isNotEmpty(this.videoUrl) && !FileUtil.accessSync(this.videoUrl)) {
|
|
|
+ // 检查文件是否存在,但跳过网络URL(WebDAV)
|
|
|
+ if (StrUtil.isNotEmpty(this.videoUrl) &&
|
|
|
+ !this.videoUrl.startsWith('http://') &&
|
|
|
+ !this.videoUrl.startsWith('https://') &&
|
|
|
+ !FileUtil.accessSync(this.videoUrl)) {
|
|
|
ToastUtil.showToast(Utility.resourceToString(getContext(), $r('app.string.file_not_exist')))
|
|
|
} else {
|
|
|
ToastUtil.showToast(getContext()
|
|
|
@@ -13193,6 +13335,58 @@ export struct LocalMusic {
|
|
|
try {
|
|
|
Logger.info(`heanup 处理歌单播放请求: ${playlistName}, 歌曲数量: ${songFilePaths.length}, 开始索引: ${startIndex}`)
|
|
|
|
|
|
+ // 检查是否为WebDAV播放请求
|
|
|
+ if (playlistId === 'webdav-playlist') {
|
|
|
+ Logger.info(`heanup 检测到WebDAV播放请求,直接从全局上下文获取歌曲数据`)
|
|
|
+ const globalContext = GlobalContext.getContext();
|
|
|
+
|
|
|
+ // 先检查GlobalContext中是否有数据
|
|
|
+ const allKeys = globalContext['_objects'] ? Array.from(globalContext['_objects'].keys()) : [];
|
|
|
+ Logger.info(`heanup GlobalContext中的所有键: ${JSON.stringify(allKeys)}`);
|
|
|
+
|
|
|
+ const videoItems = globalContext.getObject('videoItems') as VideoItem[];
|
|
|
+ const currentPlayIndex = globalContext.getObject('currentPlayIndex') as number;
|
|
|
+
|
|
|
+ Logger.info(`heanup 从GlobalContext获取数据: videoItems长度=${videoItems?.length || 0}, currentPlayIndex=${currentPlayIndex}`);
|
|
|
+
|
|
|
+ if (videoItems && videoItems.length > 0) {
|
|
|
+ Logger.info(`heanup 从全局上下文获取到WebDAV歌曲列表,长度:${videoItems.length}`)
|
|
|
+ // 验证歌曲数据是否完整
|
|
|
+ for (let i = 0; i < Math.min(3, videoItems.length); i++) {
|
|
|
+ Logger.info(`heanup 歌曲[${i}]: ${videoItems[i]?.name}, 路径: ${videoItems[i]?.filePath}`)
|
|
|
+ }
|
|
|
+ this.finishLoadingPlaylist(videoItems, startIndex, playlistName)
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ Logger.error(`heanup 无法从全局上下文获取WebDAV歌曲数据,尝试使用传入的文件路径创建备用数据`)
|
|
|
+
|
|
|
+ // 备用方案:直接使用传入的文件路径创建VideoItem
|
|
|
+ const fallbackVideoItems: VideoItem[] = [];
|
|
|
+ for (let i = 0; i < songFilePaths.length; i++) {
|
|
|
+ const fileName = songFilePaths[i].split('/').pop() || `WebDAV歌曲${i+1}`;
|
|
|
+ const videoItem = new VideoItem(
|
|
|
+ fileName.replace(/\.(flac|mp3|wav|m4a)$/i, ''), // name (去掉扩展名)
|
|
|
+ i.toString(), // id
|
|
|
+ songFilePaths[i], // filePath (URL)
|
|
|
+ CommonConstants.TYPE_INTERNET, // type
|
|
|
+ 0, // fileSize
|
|
|
+ "0", // time
|
|
|
+ undefined, // pixelMap
|
|
|
+ undefined, // size
|
|
|
+ undefined, // pixelMapPath
|
|
|
+ "WebDAV艺术家", // artist
|
|
|
+ undefined, // album
|
|
|
+ fileName // fileName
|
|
|
+ );
|
|
|
+ fallbackVideoItems.push(videoItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ Logger.info(`heanup 使用备用方案创建了${fallbackVideoItems.length}首WebDAV歌曲`)
|
|
|
+ this.finishLoadingPlaylist(fallbackVideoItems, startIndex, playlistName)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 从数据库重新加载这些歌曲,使用索引记录位置以保持顺序
|
|
|
const songMap: Map<number, VideoItem> = new Map()
|
|
|
let completedQueries = 0
|