|
@@ -97,6 +97,7 @@ 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';
|
|
|
import FileManager from '../common/util/FileManager';
|
|
import FileManager from '../common/util/FileManager';
|
|
|
|
|
+import { lyricService, SongData } from '../common/service/LyricService';
|
|
|
|
|
|
|
|
import { HSBColorPicker, HSBColorPickerLayout } from '@keke/color-picker'
|
|
import { HSBColorPicker, HSBColorPickerLayout } from '@keke/color-picker'
|
|
|
import app from '@system.app';
|
|
import app from '@system.app';
|
|
@@ -194,8 +195,8 @@ function isSmbType(type: number): boolean {
|
|
|
return type === CommonConstants.TYPE_SMB;
|
|
return type === CommonConstants.TYPE_SMB;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function isNavidromeType(type: number): boolean {
|
|
|
|
|
- return type === CommonConstants.TYPE_NAVIDROME;
|
|
|
|
|
|
|
+function isNavidromeType(type: number | undefined): boolean {
|
|
|
|
|
+ return type !== undefined && type === CommonConstants.TYPE_NAVIDROME;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function isFtpType(type: number): boolean {
|
|
function isFtpType(type: number): boolean {
|
|
@@ -206,12 +207,12 @@ function isBaiduType(type: number): boolean {
|
|
|
return type === CommonConstants.TYPE_BAIDU;
|
|
return type === CommonConstants.TYPE_BAIDU;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function isJellyfinType(type: number): boolean {
|
|
|
|
|
- return type === CommonConstants.TYPE_JELLYFIN;
|
|
|
|
|
|
|
+function isJellyfinType(type: number | undefined): boolean {
|
|
|
|
|
+ return type !== undefined && type === CommonConstants.TYPE_JELLYFIN;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function isEmbyType(type: number): boolean {
|
|
|
|
|
- return type === CommonConstants.TYPE_EMBY;
|
|
|
|
|
|
|
+function isEmbyType(type: number | undefined): boolean {
|
|
|
|
|
+ return type !== undefined && type === CommonConstants.TYPE_EMBY;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function isRemoteCloudType(type: number): boolean {
|
|
function isRemoteCloudType(type: number): boolean {
|
|
@@ -9822,276 +9823,137 @@ export struct LocalMusic {
|
|
|
this.lyricControllerSingle.setLyric(null)
|
|
this.lyricControllerSingle.setLyric(null)
|
|
|
let jiaMilyricPath = lyricPath.substring(0, lyricPath.lastIndexOf('.')) + '.lrcc'
|
|
let jiaMilyricPath = lyricPath.substring(0, lyricPath.lastIndexOf('.')) + '.lrcc'
|
|
|
console.log("onecold lyricPath =" + lyricPath)
|
|
console.log("onecold lyricPath =" + lyricPath)
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 检查内嵌歌词
|
|
|
let neiqianLrc = ''
|
|
let neiqianLrc = ''
|
|
|
let lyContent = this.currentSong?.lyricContent
|
|
let lyContent = this.currentSong?.lyricContent
|
|
|
- if(lyContent&&StrUtil.isNotEmpty(lyContent)){//取数据库里面的歌词lyContent
|
|
|
|
|
|
|
+ if(lyContent && StrUtil.isNotEmpty(lyContent)){
|
|
|
neiqianLrc = lyContent
|
|
neiqianLrc = lyContent
|
|
|
}
|
|
}
|
|
|
- if (StrUtil.isNotEmpty(neiqianLrc) && !isOnLineAndToast&&!isLocal&&!isLocal) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (StrUtil.isNotEmpty(neiqianLrc) && !isOnLineAndToast && !isLocal) {
|
|
|
console.log("onecold 找到内嵌歌词 neiqianLrc =" + neiqianLrc)
|
|
console.log("onecold 找到内嵌歌词 neiqianLrc =" + neiqianLrc)
|
|
|
- //赋值给this.lyricContent,播控中心才可以显示歌词
|
|
|
|
|
|
|
+ // Navidrome JSON歌词转换
|
|
|
if (this.currentSong && isNavidromeType(this.currentSong.type)) {
|
|
if (this.currentSong && isNavidromeType(this.currentSong.type)) {
|
|
|
- //这里判断如果是Navidrome的歌词,需要把json格式的歌词转化下lrc标准格式
|
|
|
|
|
const convertedLyric = LyricUtil.convertNavidromeJsonLyricToLrc(neiqianLrc);
|
|
const convertedLyric = LyricUtil.convertNavidromeJsonLyricToLrc(neiqianLrc);
|
|
|
if (convertedLyric) {
|
|
if (convertedLyric) {
|
|
|
neiqianLrc = convertedLyric;
|
|
neiqianLrc = convertedLyric;
|
|
|
console.log("onecold Navidrome歌词转换成功");
|
|
console.log("onecold Navidrome歌词转换成功");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- this.lyricContent = neiqianLrc
|
|
|
|
|
- // 将文件内容按行分割成字符串数组
|
|
|
|
|
- let lines = neiqianLrc.split('\n').map(line => line.trim());
|
|
|
|
|
- // 3.解析歌词
|
|
|
|
|
- let lyric = this.parser.parse(lines);
|
|
|
|
|
- // 4.设置歌词
|
|
|
|
|
- this.lyricController.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerXF.setLyric(lyric)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(lyric)
|
|
|
|
|
|
|
+ this.setLyricToControllers(neiqianLrc);
|
|
|
return
|
|
return
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 2. 尝试从服务器获取歌词 (Navidrome/Jellyfin/Emby)
|
|
|
|
|
+ if (this.currentSong && (isJellyfinType(this.currentSong.type)|| isEmbyType(this.currentSong.type))) {
|
|
|
|
|
+ const manager = RemoteDriveManager.getInstance();
|
|
|
|
|
+ const getAccount = (accountId: string) => manager.getWebDavAccountById(accountId);
|
|
|
|
|
+
|
|
|
|
|
+ // 将currentSong转换为SongData接口
|
|
|
|
|
+ const songData: SongData = {
|
|
|
|
|
+ webdav_account_id: this.currentSong.webdav_account_id,
|
|
|
|
|
+ artist: this.currentSong.artist,
|
|
|
|
|
+ name: this.currentSong.name,
|
|
|
|
|
+ webdav_id: this.currentSong.webdav_id,
|
|
|
|
|
+ lyricIndex: this.currentSong.lyricIndex,
|
|
|
|
|
+ type: this.currentSong.type
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- // 检查是否为 Jellyfin 类型的歌曲,如果是则从 Jellyfin 服务器获取歌词
|
|
|
|
|
- if (this.currentSong && isJellyfinType(this.currentSong.type)) {
|
|
|
|
|
- console.info('heanup', '检测到Jellyfin类型歌曲,尝试从Jellyfin服务器获取歌词');
|
|
|
|
|
- try {
|
|
|
|
|
- const manager = RemoteDriveManager.getInstance();
|
|
|
|
|
- const accountId = this.currentSong.webdav_account_id;
|
|
|
|
|
- if (!accountId) {
|
|
|
|
|
- throw new Error('Jellyfin账号ID不可用');
|
|
|
|
|
- }
|
|
|
|
|
- const account = await manager.getWebDavAccountById(accountId);
|
|
|
|
|
- if (!account) {
|
|
|
|
|
- throw new Error('Jellyfin账号不可用');
|
|
|
|
|
- }
|
|
|
|
|
- const itemId = this.currentSong.webdav_id || '';
|
|
|
|
|
- if (!itemId) {
|
|
|
|
|
- throw new Error('Jellyfin歌曲ID不可用');
|
|
|
|
|
- }
|
|
|
|
|
- const jellyfinLyric = await jellyfinApi.getLyric(account, itemId);
|
|
|
|
|
-
|
|
|
|
|
- if (StrUtil.isNotEmpty(jellyfinLyric)) {
|
|
|
|
|
- console.info('heanup', '成功从Jellyfin服务器获取到歌词');
|
|
|
|
|
- this.lyricContent = jellyfinLyric;
|
|
|
|
|
- let lines = jellyfinLyric.split('\n').map(line => line.trim());
|
|
|
|
|
- let lyric = this.parser.parse(lines);
|
|
|
|
|
- this.lyricController.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerXF.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerSingle.setLyric(lyric);
|
|
|
|
|
- this.showSingleLyric = true;
|
|
|
|
|
- // 保存歌词到本地
|
|
|
|
|
- this.saveDataToFile(jellyfinLyric, lyricPath, false);
|
|
|
|
|
- return;
|
|
|
|
|
- } else {
|
|
|
|
|
- console.info('heanup', 'Jellyfin服务器未返回歌词,继续尝试其他方式');
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- const err = error as Error;
|
|
|
|
|
- console.info('heanup', `从Jellyfin服务器获取歌词失败: ${err.message}`);
|
|
|
|
|
|
|
+ let serverLyric = '';
|
|
|
|
|
+ if (!serverLyric && isJellyfinType(songData.type)) {
|
|
|
|
|
+ serverLyric = await lyricService.fetchJellyfinLyric(songData, getAccount);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!serverLyric && isEmbyType(songData.type)) {
|
|
|
|
|
+ serverLyric = await lyricService.fetchEmbyLyric(songData, getAccount);
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- // 检查是否为 Emby 类型的歌曲,如果是则从 Emby 服务器获取歌词
|
|
|
|
|
- if (this.currentSong && isEmbyType(this.currentSong.type)) {
|
|
|
|
|
- console.info('heanup', '检测到Emby类型歌曲,尝试从Emby服务器获取歌词');
|
|
|
|
|
- try {
|
|
|
|
|
- const manager = RemoteDriveManager.getInstance();
|
|
|
|
|
- const accountId = this.currentSong.webdav_account_id;
|
|
|
|
|
- if (!accountId) {
|
|
|
|
|
- throw new Error('Emby账号ID不可用');
|
|
|
|
|
- }
|
|
|
|
|
- const account = await manager.getWebDavAccountById(accountId);
|
|
|
|
|
- if (!account) {
|
|
|
|
|
- throw new Error('Emby账号不可用');
|
|
|
|
|
- }
|
|
|
|
|
- const itemId = this.currentSong.webdav_id || '';
|
|
|
|
|
- const lyricIndex = this.currentSong.lyricIndex; // 从歌曲信息中获取歌词索引
|
|
|
|
|
- if (!itemId) {
|
|
|
|
|
- throw new Error('Emby歌曲ID不可用');
|
|
|
|
|
- }
|
|
|
|
|
- if (lyricIndex === undefined || lyricIndex === null) {
|
|
|
|
|
- console.info('heanup', 'Emby歌曲没有歌词索引,跳过获取歌词');
|
|
|
|
|
- } else {
|
|
|
|
|
- const embyLyric = await embyApi.getLyric(account, itemId, lyricIndex);
|
|
|
|
|
-
|
|
|
|
|
- if (StrUtil.isNotEmpty(embyLyric)) {
|
|
|
|
|
- console.info('heanup', '成功从Emby服务器获取到歌词');
|
|
|
|
|
- this.lyricContent = embyLyric;
|
|
|
|
|
- let lines = embyLyric.split('\n').map(line => line.trim());
|
|
|
|
|
- let lyric = this.parser.parse(lines);
|
|
|
|
|
- this.lyricController.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerXF.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerSingle.setLyric(lyric);
|
|
|
|
|
- this.showSingleLyric = true;
|
|
|
|
|
- // 保存歌词到本地
|
|
|
|
|
- this.saveDataToFile(embyLyric, lyricPath, false);
|
|
|
|
|
- return;
|
|
|
|
|
- } else {
|
|
|
|
|
- console.info('heanup', 'Emby服务器未返回歌词,继续尝试其他方式');
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- const err = error as Error;
|
|
|
|
|
- console.info('heanup', `从Emby服务器获取歌词失败: ${err.message}`);
|
|
|
|
|
|
|
+ if (serverLyric) {
|
|
|
|
|
+ this.setLyricToControllers(serverLyric, lyricPath);
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 3. 尝试在线歌词API
|
|
|
if (isOnLineAndToast || ((!FileUtil.accessSync(lyricPath) && !FileUtil.accessSync(jiaMilyricPath))
|
|
if (isOnLineAndToast || ((!FileUtil.accessSync(lyricPath) && !FileUtil.accessSync(jiaMilyricPath))
|
|
|
&& !Utility.isVideoByExtension(this.videoUrl))) {
|
|
&& !Utility.isVideoByExtension(this.videoUrl))) {
|
|
|
- if (this.currentSong !== undefined) {
|
|
|
|
|
- // ToastUtil.showShort('正在为你搜索在线歌词!')
|
|
|
|
|
- //判断是不是赞助会员,是会员的话才开启歌词功能
|
|
|
|
|
- // if (!this.isDebug) {
|
|
|
|
|
- // if (!Utility.isNoble()) {
|
|
|
|
|
- // LogUtil.debug("onecold 不是赞助会员")
|
|
|
|
|
- // return
|
|
|
|
|
- // }
|
|
|
|
|
- // if(!Utility.isPassInstallTime(33)){
|
|
|
|
|
- // LogUtil.debug("onecold not pass time")
|
|
|
|
|
- // // LogUtil.debug("onecold 用户安装app没超过12天" )
|
|
|
|
|
- // return
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- let artist = this.currentSong?.artist
|
|
|
|
|
- if (artist === undefined) {
|
|
|
|
|
- artist = ''
|
|
|
|
|
- }
|
|
|
|
|
- if (isApi2 === undefined) {
|
|
|
|
|
- isApi2 = false
|
|
|
|
|
- }
|
|
|
|
|
- NetAxiosUtil.getLyric(this.name, artist, isApi2).then((res) => {
|
|
|
|
|
-
|
|
|
|
|
- // LogUtil.debug("onecold res =" + res)
|
|
|
|
|
- if (StrUtil.isNotEmpty(res) && res !== 'unknown' && res !== 'Timeout was reached') {
|
|
|
|
|
-
|
|
|
|
|
- if (StrUtil.isNotEmpty(res)) {
|
|
|
|
|
- this.lyricContent = res
|
|
|
|
|
- let lines = res.split('\n').map(line => line.trim());
|
|
|
|
|
-
|
|
|
|
|
- // 3.解析歌词
|
|
|
|
|
- let lyric = this.parser.parse(lines);
|
|
|
|
|
- // 4.设置歌词
|
|
|
|
|
- this.lyricController.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerXF.setLyric(lyric)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(lyric)
|
|
|
|
|
- this.showSingleLyric = true
|
|
|
|
|
- // 4.保存歌词文件lyric到本地
|
|
|
|
|
- //2025年8月28日歌词不再加密下载
|
|
|
|
|
- this.saveDataToFile(res, lyricPath, false)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- this.lyricController.setLyric(null)
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
- if (isOnLineAndToast) {
|
|
|
|
|
- ToastUtil.showShort('未获取到歌词!')
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- this.lyricController.setLyric(null)
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
- if (isOnLineAndToast) {
|
|
|
|
|
- ToastUtil.showShort('未获取到歌词!')
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- } else {
|
|
|
|
|
- this.lyricController.setLyric(null)
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
- if (isOnLineAndToast) {
|
|
|
|
|
- ToastUtil.showShort('未获取到歌词!')
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return
|
|
|
|
|
|
|
+ this.fetchOnlineLyric(lyricPath, isOnLineAndToast || false, isApi2);
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 4. 从本地文件读取歌词
|
|
|
|
|
+ await this.loadLyricFromFile(lyricPath, jiaMilyricPath, isLocal || false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从本地文件加载歌词
|
|
|
|
|
+ */
|
|
|
|
|
+ private async loadLyricFromFile(lyricPath: string, jiaMilyricPath: string, isLocal: boolean): Promise<void> {
|
|
|
try {
|
|
try {
|
|
|
let isJiaMi = false;
|
|
let isJiaMi = false;
|
|
|
- let realLyricPath = lyricPath
|
|
|
|
|
|
|
+ let realLyricPath = lyricPath;
|
|
|
|
|
+
|
|
|
if (FileUtil.accessSync(jiaMilyricPath)) {
|
|
if (FileUtil.accessSync(jiaMilyricPath)) {
|
|
|
- isJiaMi = true
|
|
|
|
|
- realLyricPath = jiaMilyricPath
|
|
|
|
|
|
|
+ isJiaMi = true;
|
|
|
|
|
+ realLyricPath = jiaMilyricPath;
|
|
|
console.info("onecold 找到加密本地歌词 ");
|
|
console.info("onecold 找到加密本地歌词 ");
|
|
|
} else {
|
|
} else {
|
|
|
- isJiaMi = false
|
|
|
|
|
- realLyricPath = lyricPath
|
|
|
|
|
-
|
|
|
|
|
|
|
+ isJiaMi = false;
|
|
|
|
|
+ realLyricPath = lyricPath;
|
|
|
console.info("onecold 找到本地歌词 ");
|
|
console.info("onecold 找到本地歌词 ");
|
|
|
}
|
|
}
|
|
|
- // 3.读取文件内容并指定编码为 UTF-8
|
|
|
|
|
- let file = fs.openSync(realLyricPath, fs.OpenMode.READ_ONLY);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 读取文件内容
|
|
|
|
|
+ let file = fs.openSync(realLyricPath, fs.OpenMode.READ_ONLY);
|
|
|
const stat = await fileIo.stat(file.fd);
|
|
const stat = await fileIo.stat(file.fd);
|
|
|
const arrayBuffer = new ArrayBuffer(stat.size);
|
|
const arrayBuffer = new ArrayBuffer(stat.size);
|
|
|
|
|
+
|
|
|
fs.read(file.fd, arrayBuffer)
|
|
fs.read(file.fd, arrayBuffer)
|
|
|
.then((readLen: number) => {
|
|
.then((readLen: number) => {
|
|
|
console.info("read file data succeed");
|
|
console.info("read file data succeed");
|
|
|
- // let buf = buffer.from(arrayBuffer, 0, readLen);
|
|
|
|
|
-
|
|
|
|
|
let buf = new Uint8Array(arrayBuffer, 0, readLen);
|
|
let buf = new Uint8Array(arrayBuffer, 0, readLen);
|
|
|
- // 检查 buf 是否为空
|
|
|
|
|
|
|
+
|
|
|
if (buf.length === 0) {
|
|
if (buf.length === 0) {
|
|
|
throw new Error("Buffer is empty after reading the file");
|
|
throw new Error("Buffer is empty after reading the file");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
// 检测文件编码
|
|
// 检测文件编码
|
|
|
- // let detectedEncoding = chardet.detect(buf);
|
|
|
|
|
- // console.info("onecoldT Detected encoding: " + detectedEncoding);
|
|
|
|
|
- let detectedEncoding = this.detect(arrayBuffer)
|
|
|
|
|
|
|
+ let detectedEncoding = this.detect(arrayBuffer);
|
|
|
console.info("onecoldT Detected encoding: " + detectedEncoding);
|
|
console.info("onecoldT Detected encoding: " + detectedEncoding);
|
|
|
|
|
+
|
|
|
// 使用检测到的编码解码,解决中文乱码问题
|
|
// 使用检测到的编码解码,解决中文乱码问题
|
|
|
let textDecoder = new util.TextDecoder(detectedEncoding || 'utf-8');
|
|
let textDecoder = new util.TextDecoder(detectedEncoding || 'utf-8');
|
|
|
console.info("onecoldT Detected textDecoder: " + textDecoder);
|
|
console.info("onecoldT Detected textDecoder: " + textDecoder);
|
|
|
let fileContent = textDecoder.decode(buf);
|
|
let fileContent = textDecoder.decode(buf);
|
|
|
console.info(`onecoldT The content of file1: ${fileContent}`);
|
|
console.info(`onecoldT The content of file1: ${fileContent}`);
|
|
|
- //解密
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 解密
|
|
|
if (isJiaMi) {
|
|
if (isJiaMi) {
|
|
|
- fileContent = StrUtil.unit8ArrayToStr(Base64Util.decodeSync(fileContent))
|
|
|
|
|
|
|
+ fileContent = StrUtil.unit8ArrayToStr(Base64Util.decodeSync(fileContent));
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
console.info(`onecold The content of file2: ${fileContent}`);
|
|
console.info(`onecold The content of file2: ${fileContent}`);
|
|
|
- this.lyricContent = fileContent
|
|
|
|
|
- if(isLocal){//编辑标签选择本地歌词需要赋值给this.lyricConStr
|
|
|
|
|
- this.lyricConStr = fileContent
|
|
|
|
|
|
|
+ this.lyricContent = fileContent;
|
|
|
|
|
+
|
|
|
|
|
+ if(isLocal){
|
|
|
|
|
+ // 编辑标签选择本地歌词需要赋值给this.lyricConStr
|
|
|
|
|
+ this.lyricConStr = fileContent;
|
|
|
}
|
|
}
|
|
|
- // 将文件内容按行分割成字符串数组
|
|
|
|
|
- let lines = fileContent.split('\n').map(line => line.trim());
|
|
|
|
|
- console.info(`onecold The content of file: ${fileContent}`);
|
|
|
|
|
- // 3.解析歌词
|
|
|
|
|
- let lyric = this.parser.parse(lines);
|
|
|
|
|
-
|
|
|
|
|
- // 4.设置歌词
|
|
|
|
|
- this.lyricController.setLyric(lyric);
|
|
|
|
|
- this.lyricControllerXF.setLyric(lyric)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(lyric)
|
|
|
|
|
-
|
|
|
|
|
- this.showSingleLyric = true
|
|
|
|
|
|
|
+
|
|
|
|
|
+ this.setLyricToControllers(fileContent);
|
|
|
console.info(`The content of file: ${fileContent}`);
|
|
console.info(`The content of file: ${fileContent}`);
|
|
|
} catch (chardetError) {
|
|
} catch (chardetError) {
|
|
|
console.error("chardet.detect failed with error: " + chardetError.message);
|
|
console.error("chardet.detect failed with error: " + chardetError.message);
|
|
|
- this.lyricController.setLyric(null);
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
.catch((err: BusinessError) => {
|
|
.catch((err: BusinessError) => {
|
|
|
- this.lyricController.setLyric(null)
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
console.error("read file data failed with error message: " + err.message + ", error code: " + err.code);
|
|
console.error("read file data failed with error message: " + err.message + ", error code: " + err.code);
|
|
|
})
|
|
})
|
|
|
.catch((err: Error) => {
|
|
.catch((err: Error) => {
|
|
|
- this.lyricController.setLyric(null)
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
console.error("read file 2 data failed with error message: " + err.message);
|
|
console.error("read file 2 data failed with error message: " + err.message);
|
|
|
})
|
|
})
|
|
|
.finally(() => {
|
|
.finally(() => {
|
|
@@ -10099,12 +9961,9 @@ export struct LocalMusic {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- this.lyricController.setLyric(null)
|
|
|
|
|
- this.lyricControllerSingle.setLyric(null)
|
|
|
|
|
- this.lyricControllerXF.setLyric(null)
|
|
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
Logger.error(TAG, 'init Lyric failed with err: ' + JSON.stringify(error));
|
|
Logger.error(TAG, 'init Lyric failed with err: ' + JSON.stringify(error));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
detect(data: ArrayBuffer): string {
|
|
detect(data: ArrayBuffer): string {
|
|
@@ -10122,6 +9981,70 @@ export struct LocalMusic {
|
|
|
return detected;
|
|
return detected;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 设置歌词到所有控制器
|
|
|
|
|
+ * @param lyricText 歌词文本
|
|
|
|
|
+ * @param savePath 可选,如果提供则保存到本地文件
|
|
|
|
|
+ */
|
|
|
|
|
+ private setLyricToControllers(lyricText: string, savePath?: string): void {
|
|
|
|
|
+ if (StrUtil.isEmpty(lyricText)) {
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.lyricContent = lyricText;
|
|
|
|
|
+ let lines = lyricText.split('\n').map(line => line.trim());
|
|
|
|
|
+ let lyric = this.parser.parse(lines);
|
|
|
|
|
+
|
|
|
|
|
+ this.lyricController.setLyric(lyric);
|
|
|
|
|
+ this.lyricControllerXF.setLyric(lyric);
|
|
|
|
|
+ this.lyricControllerSingle.setLyric(lyric);
|
|
|
|
|
+ this.showSingleLyric = true;
|
|
|
|
|
+
|
|
|
|
|
+ // 如果提供了保存路径,保存歌词到本地
|
|
|
|
|
+ if (savePath) {
|
|
|
|
|
+ this.saveDataToFile(lyricText, savePath, false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 清空所有歌词控制器
|
|
|
|
|
+ */
|
|
|
|
|
+ private clearLyricControllers(): void {
|
|
|
|
|
+ this.lyricController.setLyric(null);
|
|
|
|
|
+ this.lyricControllerXF.setLyric(null);
|
|
|
|
|
+ this.lyricControllerSingle.setLyric(null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从在线API获取歌词
|
|
|
|
|
+ */
|
|
|
|
|
+ private fetchOnlineLyric(lyricPath: string, isOnLineAndToast: boolean, isApi2?: boolean): void {
|
|
|
|
|
+ if (!this.currentSong) {
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
|
|
+ if (isOnLineAndToast) {
|
|
|
|
|
+ ToastUtil.showShort('未获取到歌词!');
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let artist = this.currentSong.artist || '';
|
|
|
|
|
+ if (isApi2 === undefined) {
|
|
|
|
|
+ isApi2 = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ NetAxiosUtil.getLyric(this.name, artist, isApi2).then((res) => {
|
|
|
|
|
+ if (StrUtil.isNotEmpty(res) && res !== 'unknown' && res !== 'Timeout was reached') {
|
|
|
|
|
+ this.setLyricToControllers(res, lyricPath);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.clearLyricControllers();
|
|
|
|
|
+ if (isOnLineAndToast) {
|
|
|
|
|
+ ToastUtil.showShort('未获取到歌词!');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
//初始化悬浮歌词的自定义设置
|
|
//初始化悬浮歌词的自定义设置
|
|
|
initPipLyricSetting() {
|
|
initPipLyricSetting() {
|
|
|
this.lyricControllerXF
|
|
this.lyricControllerXF
|