|
@@ -90,6 +90,7 @@ import { RemoteCacheType, resolveCacheFilePath } from '../common/network/RemoteS
|
|
|
import { findWebDavCacheIfExists, triggerWebDavCacheDownload } from '../common/network/WebDavFileCache';
|
|
import { findWebDavCacheIfExists, triggerWebDavCacheDownload } from '../common/network/WebDavFileCache';
|
|
|
import { navidromeApi } from '../common/network/NavidromeApi';
|
|
import { navidromeApi } from '../common/network/NavidromeApi';
|
|
|
import { jellyfinApi } from '../common/network/JellyfinApi';
|
|
import { jellyfinApi } from '../common/network/JellyfinApi';
|
|
|
|
|
+import { embyApi } from '../common/network/EmbyApi';
|
|
|
import { ServerLogUtil } from '../common/util/ServerLogUtil';
|
|
import { ServerLogUtil } from '../common/util/ServerLogUtil';
|
|
|
import { ensureSmbFileStreaming, SmbStreamingMeta } from '../common/network/SmbFileCache';
|
|
import { ensureSmbFileStreaming, SmbStreamingMeta } from '../common/network/SmbFileCache';
|
|
|
import { ensureBaiduFileCached } from '../common/network/BaiduFileCache';
|
|
import { ensureBaiduFileCached } from '../common/network/BaiduFileCache';
|
|
@@ -176,6 +177,7 @@ function getTypeOrder(type: number) {
|
|
|
case CommonConstants.TYPE_FTP:
|
|
case CommonConstants.TYPE_FTP:
|
|
|
case CommonConstants.TYPE_BAIDU:
|
|
case CommonConstants.TYPE_BAIDU:
|
|
|
case CommonConstants.TYPE_JELLYFIN:
|
|
case CommonConstants.TYPE_JELLYFIN:
|
|
|
|
|
+ case CommonConstants.TYPE_EMBY:
|
|
|
return 3;
|
|
return 3;
|
|
|
default:
|
|
default:
|
|
|
return 4; // Unknown types, if any, go last
|
|
return 4; // Unknown types, if any, go last
|
|
@@ -206,8 +208,12 @@ function isJellyfinType(type: number): boolean {
|
|
|
return type === CommonConstants.TYPE_JELLYFIN;
|
|
return type === CommonConstants.TYPE_JELLYFIN;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function isEmbyType(type: number): boolean {
|
|
|
|
|
+ return type === CommonConstants.TYPE_EMBY;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function isRemoteCloudType(type: number): boolean {
|
|
function isRemoteCloudType(type: number): boolean {
|
|
|
- return isWebDavType(type) || isSmbType(type) || isNavidromeType(type) || isFtpType(type) || isBaiduType(type) || isJellyfinType(type);
|
|
|
|
|
|
|
+ return isWebDavType(type) || isSmbType(type) || isNavidromeType(type) || isFtpType(type) || isBaiduType(type) || isJellyfinType(type) || isEmbyType(type);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function getShareNameFromFilePath(filePath?: string): string | undefined {
|
|
function getShareNameFromFilePath(filePath?: string): string | undefined {
|
|
@@ -591,6 +597,25 @@ async function setVideoUrlForSong(song: VideoItem, options?: MetadataExtractionO
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (isEmbyType(song.type) && song.webdav_account_id) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const manager = RemoteDriveManager.getInstance();
|
|
|
|
|
+ const account = await manager.getWebDavAccountById(song.webdav_account_id);
|
|
|
|
|
+ if (!account) {
|
|
|
|
|
+ throw new Error('Emby账号不可用');
|
|
|
|
|
+ }
|
|
|
|
|
+ const embySongId = song.remote_rel_path || song.id || song.filePath;
|
|
|
|
|
+ const streamUrl = await embyApi.buildStreamUrl(account, embySongId);
|
|
|
|
|
+ void ServerLogUtil.info(TAG, `Emby 流地址构建成功: ${streamUrl}`);
|
|
|
|
|
+ void ServerLogUtil.debug(TAG, `播放songId=${embySongId}, account=${ServerLogUtil.sanitizeAccount(account)}`);
|
|
|
|
|
+ return sanitizePlaybackUrl(streamUrl);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ const err = error as Error;
|
|
|
|
|
+ void ServerLogUtil.error(TAG, `Emby URL构建失败: ${err.message}`);
|
|
|
|
|
+ throw new Error(err.message);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (isSmbType(song.type) && song.webdav_account_id) {
|
|
if (isSmbType(song.type) && song.webdav_account_id) {
|
|
|
try {
|
|
try {
|
|
|
const manager = RemoteDriveManager.getInstance();
|
|
const manager = RemoteDriveManager.getInstance();
|
|
@@ -738,6 +763,9 @@ async function setVideoUrlForSong(song: VideoItem, options?: MetadataExtractionO
|
|
|
if (isJellyfinType(song.type)) {
|
|
if (isJellyfinType(song.type)) {
|
|
|
throw new Error('Jellyfin歌曲缺少webdav_account_id,无法构建播放链接');
|
|
throw new Error('Jellyfin歌曲缺少webdav_account_id,无法构建播放链接');
|
|
|
}
|
|
}
|
|
|
|
|
+ if (isEmbyType(song.type)) {
|
|
|
|
|
+ throw new Error('Emby歌曲缺少webdav_account_id,无法构建播放链接');
|
|
|
|
|
+ }
|
|
|
Logger.info(TAG, `setVideoUrlForSong fallback直接返回原始路径: ${song.filePath}`);
|
|
Logger.info(TAG, `setVideoUrlForSong fallback直接返回原始路径: ${song.filePath}`);
|
|
|
return song.filePath;
|
|
return song.filePath;
|
|
|
}
|
|
}
|
|
@@ -1856,7 +1884,10 @@ export struct LocalMusic {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private closeLoadingProgressDialog(): void {
|
|
private closeLoadingProgressDialog(): void {
|
|
|
- DialogHelper.closeLoading();
|
|
|
|
|
|
|
+ if (!this.loadingProgressDialogId) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ DialogHelper.closeDialog(this.loadingProgressDialogId);
|
|
|
this.loadingProgressDialogId = '';
|
|
this.loadingProgressDialogId = '';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2928,14 +2959,13 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
// 初始化进度条
|
|
// 初始化进度条
|
|
|
this.progress = 0;
|
|
this.progress = 0;
|
|
|
- DialogHelper.showLoadingProgress({
|
|
|
|
|
|
|
+ this.loadingProgressDialogId = DialogHelper.showLoadingProgress({
|
|
|
progress: this.progress,
|
|
progress: this.progress,
|
|
|
backCancel: false,
|
|
backCancel: false,
|
|
|
autoCancel: false,
|
|
autoCancel: false,
|
|
|
loadColor: $r('app.color.title_bar_bg'),
|
|
loadColor: $r('app.color.title_bar_bg'),
|
|
|
fontColor: $r('app.color.title_bar_bg')
|
|
fontColor: $r('app.color.title_bar_bg')
|
|
|
});
|
|
});
|
|
|
- this.loadingProgressDialogId = 'dialog_progress';
|
|
|
|
|
|
|
|
|
|
// 计算处理总数用于进度计算
|
|
// 计算处理总数用于进度计算
|
|
|
const totalItems = uris.length;
|
|
const totalItems = uris.length;
|
|
@@ -2963,14 +2993,14 @@ export struct LocalMusic {
|
|
|
// 更新进度
|
|
// 更新进度
|
|
|
processedItems++;
|
|
processedItems++;
|
|
|
this.progress = Math.floor((processedItems / totalItems) * 100);
|
|
this.progress = Math.floor((processedItems / totalItems) * 100);
|
|
|
- DialogHelper.updateLoading(` 正在处理 ${this.progress}%`, this.progress);
|
|
|
|
|
|
|
+ DialogHelper.updateLoading(this.loadingProgressDialogId, ` 正在处理 ${this.progress}%`, this.progress);
|
|
|
|
|
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
Logger.error(TAG, 'saveVideoDatas failed with err: ' + JSON.stringify(error));
|
|
Logger.error(TAG, 'saveVideoDatas failed with err: ' + JSON.stringify(error));
|
|
|
// 即使出错也更新进度
|
|
// 即使出错也更新进度
|
|
|
processedItems++;
|
|
processedItems++;
|
|
|
this.progress = Math.floor((processedItems / totalItems) * 100);
|
|
this.progress = Math.floor((processedItems / totalItems) * 100);
|
|
|
- DialogHelper.updateLoading(` 正在处理 ${this.progress}%`, this.progress);
|
|
|
|
|
|
|
+ DialogHelper.updateLoading(this.loadingProgressDialogId, ` 正在处理 ${this.progress}%`, this.progress);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// 关闭进度条
|
|
// 关闭进度条
|
|
@@ -2991,14 +3021,13 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
let newUris: string[] = [];
|
|
let newUris: string[] = [];
|
|
|
this.progress = 0
|
|
this.progress = 0
|
|
|
- DialogHelper.showLoadingProgress({
|
|
|
|
|
|
|
+ this.loadingProgressDialogId = DialogHelper.showLoadingProgress({
|
|
|
progress: this.progress,
|
|
progress: this.progress,
|
|
|
backCancel: false,
|
|
backCancel: false,
|
|
|
autoCancel: false,
|
|
autoCancel: false,
|
|
|
loadColor: this.themeColor,
|
|
loadColor: this.themeColor,
|
|
|
fontColor: this.themeColor
|
|
fontColor: this.themeColor
|
|
|
});
|
|
});
|
|
|
- this.loadingProgressDialogId = 'dialog_progress';
|
|
|
|
|
// 计算所有文件的总大小
|
|
// 计算所有文件的总大小
|
|
|
let totalSize = 0;
|
|
let totalSize = 0;
|
|
|
for (let uri of uris) {
|
|
for (let uri of uris) {
|
|
@@ -3030,7 +3059,7 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
// 计算总进度
|
|
// 计算总进度
|
|
|
this.progress = Math.floor((totalRead / totalSize) * 100);
|
|
this.progress = Math.floor((totalRead / totalSize) * 100);
|
|
|
- DialogHelper.updateLoading(`正在导入 ${this.progress}%`, this.progress);
|
|
|
|
|
|
|
+ DialogHelper.updateLoading(this.loadingProgressDialogId, `正在导入 ${this.progress}%`, this.progress);
|
|
|
|
|
|
|
|
len = await fileIo.read(sourceFile.fd, buffer);
|
|
len = await fileIo.read(sourceFile.fd, buffer);
|
|
|
}
|
|
}
|
|
@@ -7169,6 +7198,7 @@ export struct LocalMusic {
|
|
|
case CommonConstants.TYPE_FTP:
|
|
case CommonConstants.TYPE_FTP:
|
|
|
case CommonConstants.TYPE_BAIDU:
|
|
case CommonConstants.TYPE_BAIDU:
|
|
|
case CommonConstants.TYPE_JELLYFIN:
|
|
case CommonConstants.TYPE_JELLYFIN:
|
|
|
|
|
+ case CommonConstants.TYPE_EMBY:
|
|
|
// 处理网络音频播放(WebDAV/SMB)
|
|
// 处理网络音频播放(WebDAV/SMB)
|
|
|
Logger.info(`heanup 处理云端音频播放: ${item.name}, URL: ${item.filePath}`)
|
|
Logger.info(`heanup 处理云端音频播放: ${item.name}, URL: ${item.filePath}`)
|
|
|
|
|
|