|
|
@@ -1,10 +1,12 @@
|
|
|
import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
|
|
|
-import { FileUtil } from '@pura/harmony-utils';
|
|
|
+import { FileUtil, StrUtil } from '@pura/harmony-utils';
|
|
|
import { CommonConstants } from '../common/constants/CommonConstants';
|
|
|
import Logger from '../common/util/Logger';
|
|
|
import MediaTable from '../common/util/MediaTable';
|
|
|
import { Utility } from '../common/util/Utility';
|
|
|
import { VideoItem } from '../viewmodel/VideoItem';
|
|
|
+import { changeMusicCover, repairAudioMetadata } from '../common/util/MusicTagUtils';
|
|
|
+import { FFMpegTags } from '../common/util/Utility';
|
|
|
|
|
|
const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
|
|
|
|
|
|
@@ -16,6 +18,28 @@ interface MetadataRequestPayload {
|
|
|
trackCount?: string;
|
|
|
}
|
|
|
|
|
|
+interface EditMusicRequestPayload {
|
|
|
+ context: Context;
|
|
|
+ item: VideoItem;
|
|
|
+ titleStr: string;
|
|
|
+ artistStr: string;
|
|
|
+ ablumStr: string;
|
|
|
+ yearStr: string;
|
|
|
+ genreStr: string;
|
|
|
+ trackStr: string;
|
|
|
+ albumArtistStr: string;
|
|
|
+ composerStr: string;
|
|
|
+ lyricistStr: string;
|
|
|
+ commentStr: string;
|
|
|
+ discStr: string;
|
|
|
+ lyricConStr: string;
|
|
|
+ imagePathStr: string;
|
|
|
+ currentPath: string;
|
|
|
+ packName: string;
|
|
|
+ modeType: number;
|
|
|
+ autoParseMusicName: boolean;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* Defines the event handler to be called when the worker thread receives a message sent by the host thread.
|
|
|
@@ -52,6 +76,9 @@ workerPort.onmessage = async (e: MessageEvents) => {
|
|
|
e.data.data4 as MetadataRequestPayload
|
|
|
);
|
|
|
break;
|
|
|
+ case 6://编辑内嵌音乐元数据和封面
|
|
|
+ await handleEditMusic(e.data.data as EditMusicRequestPayload);
|
|
|
+ break;
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -344,6 +371,203 @@ async function analyzeCachedMediaMetadata(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+async function updateInfoDb(
|
|
|
+ context: Context,
|
|
|
+ filePath: string,
|
|
|
+ titleStr: string,
|
|
|
+ artistStr: string,
|
|
|
+ albumStr: string,
|
|
|
+ lyricConStr: string,
|
|
|
+ yearStr: string,
|
|
|
+ genreStr: string,
|
|
|
+ trackStr: string,
|
|
|
+ albumArtistStr: string,
|
|
|
+ composerStr: string,
|
|
|
+ lyricistStr: string,
|
|
|
+ commentStr: string,
|
|
|
+ discStr: string,
|
|
|
+): Promise<boolean> {
|
|
|
+ const table: MediaTable = new MediaTable(context);
|
|
|
+ await new Promise<void>((resolve, reject) => {
|
|
|
+ table.getRdbStore(context, (err:Error) => {
|
|
|
+ err ? reject(err) : resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ return await new Promise<boolean>((resolve) => {
|
|
|
+ table.updateMediaInfo(filePath, titleStr, artistStr, albumStr, lyricConStr,
|
|
|
+ yearStr, genreStr, trackStr, albumArtistStr, composerStr, lyricistStr, commentStr, discStr,
|
|
|
+ (success: boolean, error?: string) => {
|
|
|
+ if (success) {
|
|
|
+ console.log("heanup 编辑信息成功,数据库已同步");
|
|
|
+ } else {
|
|
|
+ console.error("heanup 编辑信息数据库失败原因: " + error);
|
|
|
+ }
|
|
|
+ resolve(success);
|
|
|
+ });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+async function handleEditMusic(payload: EditMusicRequestPayload): Promise<void> {
|
|
|
+ try {
|
|
|
+ const context = payload.context;
|
|
|
+ const item = payload.item;
|
|
|
+ const titleStr = payload.titleStr;
|
|
|
+ const artistStr = payload.artistStr;
|
|
|
+ const ablumStr = payload.ablumStr;
|
|
|
+ const yearStr = payload.yearStr;
|
|
|
+ const genreStr = payload.genreStr;
|
|
|
+ const trackStr = payload.trackStr;
|
|
|
+ const albumArtistStr = payload.albumArtistStr;
|
|
|
+ const composerStr = payload.composerStr;
|
|
|
+ const lyricistStr = payload.lyricistStr;
|
|
|
+ const commentStr = payload.commentStr;
|
|
|
+ const discStr = payload.discStr;
|
|
|
+ const lyricConStr = payload.lyricConStr;
|
|
|
+ const imagePathStr = payload.imagePathStr;
|
|
|
+ const currentPath = payload.currentPath;
|
|
|
+ const packName = payload.packName;
|
|
|
+ const modeType = payload.modeType;
|
|
|
+ const autoParseMusicName = payload.autoParseMusicName;
|
|
|
+
|
|
|
+ if (!item || StrUtil.isEmpty(titleStr)) {
|
|
|
+ workerPort.postMessage({
|
|
|
+ code: 106,
|
|
|
+ success: false,
|
|
|
+ error: '标题不能为空'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let tempOutPath = '';
|
|
|
+ // 如果不是 packName 包下的文件,则直接路径用currentPath
|
|
|
+ if (!item.filePath.toLowerCase().includes(packName)) {
|
|
|
+ tempOutPath = currentPath + '/' + item.fileName;
|
|
|
+ }
|
|
|
+ console.info('heanup tempOutPath =' + tempOutPath);
|
|
|
+
|
|
|
+ let coverResult = false;
|
|
|
+ // 用户更改了封面,那就内嵌下封面
|
|
|
+ if (StrUtil.isNotEmpty(imagePathStr)) {
|
|
|
+ coverResult = await changeMusicCover(
|
|
|
+ context,
|
|
|
+ item.filePath,
|
|
|
+ imagePathStr,
|
|
|
+ true,
|
|
|
+ tempOutPath
|
|
|
+ );
|
|
|
+
|
|
|
+ if (coverResult) {
|
|
|
+ console.log('heanup 内嵌封面成功');
|
|
|
+ } else {
|
|
|
+ console.error('heanup 内嵌封面失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const metadata: FFMpegTags = {
|
|
|
+ title: titleStr,
|
|
|
+ artist: artistStr,
|
|
|
+ album: ablumStr,
|
|
|
+ TYER: yearStr,
|
|
|
+ genre: genreStr,
|
|
|
+ track: trackStr,
|
|
|
+ album_artist: albumArtistStr,
|
|
|
+ TPE2: albumArtistStr,
|
|
|
+ COMPOSER: composerStr,
|
|
|
+ lyricist: lyricistStr,
|
|
|
+ TEXT: lyricistStr,
|
|
|
+ comment: commentStr,
|
|
|
+ disc: discStr,
|
|
|
+ };
|
|
|
+
|
|
|
+ let newInput = item.filePath;
|
|
|
+ // 内嵌标签歌路径如果不是包含包名,输入newInput要赋值tempOutPath,然后tempOutPath为空
|
|
|
+ if (!item.filePath.toLowerCase().includes(packName) && FileUtil.accessSync(tempOutPath)) {
|
|
|
+ newInput = tempOutPath;
|
|
|
+ tempOutPath = '';
|
|
|
+ }
|
|
|
+ console.info('heanup repairAudioMetadata newInput =' + newInput);
|
|
|
+ console.info('heanup repairAudioMetadata tempOutPath =' + tempOutPath);
|
|
|
+ // 内嵌下标签的值,设置overwrite为true会直接修改原文件
|
|
|
+ const metadataResult = await repairAudioMetadata(
|
|
|
+ newInput,
|
|
|
+ lyricConStr,
|
|
|
+ metadata,
|
|
|
+ true,
|
|
|
+ tempOutPath
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!metadataResult) {
|
|
|
+ workerPort.postMessage({
|
|
|
+ code: 106,
|
|
|
+ success: false,
|
|
|
+ error: '内嵌音乐标签失败'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let needRefreshList = false;
|
|
|
+ if (!item.filePath.includes(packName)) {
|
|
|
+ // 内嵌成功的歌路径如果不是包含包名,则要入库
|
|
|
+ let newItem: VideoItem = await Utility.uriGetMusicAssetsFromFile(
|
|
|
+ context,
|
|
|
+ newInput,
|
|
|
+ CommonConstants.TYPE_LOCAL,
|
|
|
+ autoParseMusicName
|
|
|
+ );
|
|
|
+
|
|
|
+ const table: MediaTable = new MediaTable(context);
|
|
|
+ await new Promise<void>((resolve, reject) => {
|
|
|
+ table.getRdbStore(context, (err: Error) => {
|
|
|
+ err ? reject(err) : resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ await new Promise<void>((resolve) => {
|
|
|
+ table.insert(newItem, (id: number) => {
|
|
|
+ needRefreshList = true;
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新数据库信息
|
|
|
+ const dbResult = await updateInfoDb(
|
|
|
+ context,
|
|
|
+ item.filePath,
|
|
|
+ titleStr,
|
|
|
+ artistStr,
|
|
|
+ ablumStr,
|
|
|
+ lyricConStr,
|
|
|
+ yearStr,
|
|
|
+ genreStr,
|
|
|
+ trackStr,
|
|
|
+ albumArtistStr,
|
|
|
+ composerStr,
|
|
|
+ lyricistStr,
|
|
|
+ commentStr,
|
|
|
+ discStr
|
|
|
+ );
|
|
|
+
|
|
|
+ workerPort.postMessage({
|
|
|
+ code: 106,
|
|
|
+ success: dbResult,
|
|
|
+ coverResult: coverResult,
|
|
|
+ needRefreshList: needRefreshList,
|
|
|
+ metadataResult: metadataResult
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ const err = error as Error;
|
|
|
+ console.error('heanup doEdit worker error: ' + err.message);
|
|
|
+ workerPort.postMessage({
|
|
|
+ code: 106,
|
|
|
+ success: false,
|
|
|
+ error: err.message
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* Defines the event handler to be called when the worker receives a message that cannot be deserialized.
|