Add Tag Edit Function & Wasm for Qmc & Kgm #5

Merged
um-dev merged 17 commits from nullptr-0/web:master into master 2022-11-24 07:32:59 +00:00
Contributor

1.Add TypeScript Support for Qmc EncV2 Decryption
2.Add Wasm Acceleration for Qmc and Kgm Decryption
3.Add Support for multi-artists in Music Tag
4.Add Music Tag Edit Function

1.Add TypeScript Support for Qmc EncV2 Decryption 2.Add Wasm Acceleration for Qmc and Kgm Decryption 3.Add Support for multi-artists in Music Tag 4.Add Music Tag Edit Function
nullptr-0 added 1 commit 2022-11-20 14:44:31 +00:00
um-dev requested changes 2022-11-20 15:29:23 +00:00
um-dev left a comment
Owner

仓库里面不要提交编译产物
引入wasm的话,可以参考 qmc_wasm,将编译产物作为npm包发布,并提供源代码

仓库里面不要提交编译产物 引入wasm的话,可以参考 qmc_wasm,将编译产物作为npm包发布,并提供源代码
jixunmoe requested changes 2022-11-20 15:46:26 +00:00
@ -34,2 +36,2 @@
let audioData = oriData.slice(headerLen);
let dataLen = audioData.length;
const kgmDecrypted = await DecryptKgmWasm(oriData, raw_ext);
// 若 v2 检测失败,降级到 v1 再尝试一次
Owner

没有 v2

没有 v2
nullptr-0 marked this conversation as resolved
@ -36,0 +39,4 @@
musicDecoded = kgmDecrypted.data;
console.log('kgm wasm decoder suceeded');
} else {
console.warn('KgmWasm failed with error %s', kgmDecrypted.error || '(no error)');
Owner

no error 应为 unknown error

`no error` 应为 `unknown error`
nullptr-0 marked this conversation as resolved
@ -36,0 +44,4 @@
}
if (!musicDecoded) {
musicDecoded = new Uint8Array(oriData);
Owner

还是动态生成 mask 的方案… 直接删掉这部分也许会更好?

还是动态生成 mask 的方案… 直接删掉这部分也许会更好?
Author
Contributor

js部分作为WASM不受支持或执行失败时的fallback

js部分作为WASM不受支持或执行失败时的fallback
Owner

但是要注意这两个实现不一致。遇到报告错误的时候,排查问题会很麻烦。

看 caniuse 的数据,除了上古浏览器(如 IE 11 和以前),基本都有提供支援了:

https://caniuse.com/wasm

但是要注意这两个实现不一致。遇到报告错误的时候,排查问题会很麻烦。 看 caniuse 的数据,除了上古浏览器(如 IE 11 和以前),基本都有提供支援了: https://caniuse.com/wasm
Author
Contributor

那qmc的js部分也删掉吗(既然一般情况下都支持wasm)

那qmc的js部分也删掉吗(既然一般情况下都支持wasm)
Owner

我的看法是也可以删了。

我的看法是也可以删了。
@ -39,3 +39,3 @@
const musicMeta = await metaParseBlob(musicBlob);
const { title, artist } = GetMetaFromFile(raw_filename, musicMeta.common.title, musicMeta.common.artist);
const { title, artist } = GetMetaFromFile(raw_filename, musicMeta.common.title, musicMeta.common.artists == undefined ? musicMeta.common.artist : musicMeta.common.artists.toString());
Owner
  • musicMeta.common.artists == undefined ? musicMeta.common.artist : musicMeta.common.artists.toString() 可以替换为 String(musicMeta.common.artists || musicMeta.common.artist)
- `musicMeta.common.artists == undefined ? musicMeta.common.artist : musicMeta.common.artists.toString()` 可以替换为 `String(musicMeta.common.artists || musicMeta.common.artist)`。
nullptr-0 marked this conversation as resolved
@ -14,3 +14,3 @@
if (ext !== raw_ext) file = new Blob([buffer], { type: AudioMimeType[ext] });
const tag = await metaParseBlob(file);
const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artist);
const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString());
Owner

同上,

  • tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString() 可以替换为 String(tag.common.artists || tag.common.artist)
同上, - `tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString()` 可以替换为 `String(tag.common.artists || tag.common.artist)`。
nullptr-0 marked this conversation as resolved
@ -35,0 +37,4 @@
const mixKey1: Uint8Array = new Uint8Array([ 0x33, 0x38, 0x36, 0x5A, 0x4A, 0x59, 0x21, 0x40, 0x23, 0x2A, 0x24, 0x25, 0x5E, 0x26, 0x29, 0x28 ])
const mixKey2: Uint8Array = new Uint8Array([ 0x2A, 0x2A, 0x23, 0x21, 0x28, 0x23, 0x24, 0x25, 0x26, 0x5E, 0x61, 0x31, 0x63, 0x5A, 0x2C, 0x54 ])
const v2KeyPrefix: Uint8Array = new Uint8Array([ 0x51, 0x51, 0x4D, 0x75, 0x73, 0x69, 0x63, 0x20, 0x45, 0x6E, 0x63, 0x56, 0x32, 0x2C, 0x4B, 0x65, 0x79, 0x3A ])
Owner

未使用的变量,后面直接内嵌了

未使用的变量,后面直接内嵌了
nullptr-0 marked this conversation as resolved
@ -25,0 +27,4 @@
musicDecoded = qmcDecrypted.data;
console.log('qmc wasm decoder suceeded');
} else {
console.warn('QmcWasm failed with error %s', qmcDecrypted.error || '(no error)');
Owner

no error 应为 unknown error

`no error` 应为 `unknown error`。
nullptr-0 marked this conversation as resolved
@ -36,3 +55,3 @@
}
const tag = await metaParseBlob(audioBlob);
const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artist);
const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString());
Owner
  • tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString() 可以替换为 String(tag.common.artists || tag.common.artist)
- `tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString()` 可以替换为 `String(tag.common.artists || tag.common.artist)`。
nullptr-0 marked this conversation as resolved
@ -18,3 +18,3 @@
}
const tag = await metaParseBlob(file);
const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artist);
const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString());
Owner
  • tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString() 可以替换为 String(tag.common.artists || tag.common.artist)
- `tag.common.artists == undefined ? tag.common.artist : tag.common.artists.toString()` 可以替换为 `String(tag.common.artists || tag.common.artist)`。
nullptr-0 marked this conversation as resolved
@ -92,3 +94,3 @@
const items = filename.split(separator);
if (items.length > 1) {
if (!meta.artist) meta.artist = items[0].trim();
if (!meta.artist || meta.artist.split(split_regex).length < items[0].trim().split(split_regex).length) meta.artist = items[0].trim();
Owner

不清楚这个新增的判定的含义,加一些注释可能会比较好一点。

不清楚这个新增的判定的含义,加一些注释可能会比较好一点。
nullptr-0 marked this conversation as resolved
@ -172,0 +176,4 @@
export function RewriteMetaToMp3(audioData: Buffer, info: IMusicMeta, original: IAudioMetadata) {
const writer = new ID3Writer(audioData);
// reserve original data
Owner

reserve => preserve

`reserve` => `preserve`?
nullptr-0 marked this conversation as resolved
@ -172,0 +188,4 @@
try {
writer.setFrame(frame.id, frame.value);
} catch (e) {
throw new Error('write unknown mp3 frame failed');
Owner

可以将 frame.idframe.value 都打印到 console,然后报错

throw new Error(`failed to write ID3 tag '${frame.id}'`);

不过即便如此,更好的方法也许是提示这个错误然后继续,因为写 ID3 只是一个附加功能,而不是核心功能。

可以将 `frame.id` 和 `frame.value` 都打印到 `console`,然后报错 ```js throw new Error(`failed to write ID3 tag '${frame.id}'`); ``` 不过即便如此,更好的方法也许是提示这个错误然后继续,因为写 ID3 只是一个附加功能,而不是核心功能。
nullptr-0 marked this conversation as resolved
@ -172,0 +213,4 @@
export function RewriteMetaToFlac(audioData: Buffer, info: IMusicMeta, original: IAudioMetadata) {
const writer = new MetaFlac(audioData);
const old = original.common;
if (info.title) {
Owner

完全可以写一个包装函数,addOrReplaceTag

完全可以写一个包装函数,`addOrReplaceTag`。
Author
Contributor

Add和Replace的逻辑有差别,Add以旧tag为优先,Replace以新tag为优先,感觉即使封装了最后还是要分开调用Add和Replace

Add和Replace的逻辑有差别,Add以旧tag为优先,Replace以新tag为优先,感觉即使封装了最后还是要分开调用Add和Replace
Owner

这个函数就是用来方便覆盖现有 tag;如果还没有,就加入。

这个函数就是用来方便覆盖现有 tag;如果还没有,就加入。
@ -50,3 +50,3 @@
raw_filename,
musicMeta.common.title,
musicMeta.common.artist,
musicMeta.common.artists == undefined ? musicMeta.common.artist : musicMeta.common.artists.toString(),
Owner
  • 可以替换为 String(musicMeta.common.artists || musicMeta.common.artist)
- 可以替换为 `String(musicMeta.common.artists || musicMeta.common.artist)`。
nullptr-0 marked this conversation as resolved
@ -40,2 +41,3 @@
console.warn('try using gbk encoding to decode meta');
musicMeta.common.artist = iconv.decode(new Buffer(musicMeta.common.artist ?? ''), 'gbk');
musicMeta.common.artist = '';
if (musicMeta.common.artists == undefined) {
Owner
  • 不需要 == undefined 部分
  • 如果需要检查 undefined 值,应使用 === 操作符。
- 不需要 `== undefined` 部分 - 如果需要检查 `undefined` 值,应使用 `===` 操作符。
nullptr-0 marked this conversation as resolved
@ -42,0 +45,4 @@
}
else {
musicMeta.common.artists.forEach((artist) => artist = iconv.decode(new Buffer(artist ?? ''), 'gbk'));
musicMeta.common.artist = musicMeta.common.artists.toString();
Owner
  • 可以替换为 String(musicMeta.common.artists || musicMeta.common.artist)
- 可以替换为 `String(musicMeta.common.artists || musicMeta.common.artist)`。
Author
Contributor

但是这样改就不是gbk编码了吧

但是这样改就不是gbk编码了吧
Owner

确实忽略了 GBK 的情况,请无视之前的建议。

// 文件顶部定义
const fromGBK = (text) => iconv.decode(new Buffer(text || ''), 'gbk')

// 第 47、48 行更换为
musicMeta.common.artist = musicMeta.common.artists.map(fromGBK).join();

下面的 iconv.decode 调用也可以更改为调用这个新的包装函数。

确实忽略了 GBK 的情况,请无视之前的建议。 ```js // 文件顶部定义 const fromGBK = (text) => iconv.decode(new Buffer(text || ''), 'gbk') // 第 47、48 行更换为 musicMeta.common.artist = musicMeta.common.artists.map(fromGBK).join(); ``` 下面的 `iconv.decode` 调用也可以更改为调用这个新的包装函数。
nullptr-0 marked this conversation as resolved
@ -45,3 +53,3 @@
}
if (id) {
if (id && id !== '0') {
Owner

为什么一开始不传入一个整数值呢

为什么一开始不传入一个整数值呢
Author
Contributor

wasm版本返回的songId是string,'0'也和0一样代表无效的id

wasm版本返回的songId是string,'0'也和0一样代表无效的id
Owner

建议改一下 wasm 的返回值或 js 接收这个值的时候做类型转换。

建议改一下 wasm 的返回值或 js 接收这个值的时候做类型转换。
Author
Contributor

id本身的类型就是number | string,所以我觉得两种都应该支持吧

id本身的类型就是number | string,所以我觉得两种都应该支持吧
Owner

也行

也行
jixunmoe marked this conversation as resolved
@ -68,3 +76,3 @@
blob: await writeMetaToAudioFile({
title: info.title,
artists: info.artist.split(' _ '),
artists: info.artist.split(split_regex),
Owner

同上,为什么一开始就不使用字符串数组来储存艺术家信息?

同上,为什么一开始就不使用字符串数组来储存艺术家信息?
Author
Contributor

历史问题。原来的GetMetaFromFile返回的艺术家信息是string

历史问题。原来的GetMetaFromFile返回的艺术家信息是string
Owner

直接重构吧,不然很多代码都要字符串、数组转来转去。

明明是同一个项目里的代码…

或者写一个包装函数调用也可以,如 const isSongIdInvalid = (songId: unknown) => songId && songId !== '0';

直接重构吧,不然很多代码都要字符串、数组转来转去。 明明是同一个项目里的代码… 或者写一个包装函数调用也可以,如 `const isSongIdInvalid = (songId: unknown) => songId && songId !== '0';`
@ -89,3 +97,3 @@
return {
title: info.track_info.title,
artist: artists.join(''),
artist: artists.join(','),
Owner

意义不明的更改。需要注释。

意义不明的更改。需要注释。
Author
Contributor

与toString的结果统一格式(虽然原来的结果regex也可以匹配)

与toString的结果统一格式(虽然原来的结果regex也可以匹配)
Owner

参见上面的那条回复

参见上面的那条回复
nullptr-0 marked this conversation as resolved
@ -131,0 +146,4 @@
async handleEdit(data) {
this.showEditDialog = false;
URL.revokeObjectURL(this.editing_data.file);
if (data.picture) {
Owner

picture 换成 albumCover 也许会好一点。

`picture` 换成 `albumCover` 也许会好一点。
Author
Contributor

历史问题。为了与原来的DecryptResult保持统一

历史问题。为了与原来的DecryptResult保持统一
Owner

也行

也行
jixunmoe marked this conversation as resolved
@ -131,0 +179,4 @@
console.warn('Error while appending cover image to file ' + e);
}
this.editing_data.file = URL.createObjectURL(this.editing_data.blob);/**/
this.$notify.success({
Owner

这个提示应该没有必要,因为用户可以看到预览更新?

这个提示应该没有必要,因为用户可以看到预览更新?
Author
Contributor

可能预览更新成功了但是文件写入失败了(v1.10.2就出现了这种情况)

可能预览更新成功了但是文件写入失败了(v1.10.2就出现了这种情况)
Owner

但这样的话不应该是捕捉出错信息并提示用户吗。

我看上面还有个 try/catch 块,但是错误直接吞掉了。

但这样的话不应该是捕捉出错信息并提示用户吗。 我看上面还有个 `try/catch` 块,但是错误直接吞掉了。
nullptr-0 marked this conversation as resolved
nullptr-0 added 1 commit 2022-11-20 16:35:03 +00:00
nullptr-0 added 1 commit 2022-11-20 17:08:16 +00:00
nullptr-0 requested review from um-dev 2022-11-20 17:12:50 +00:00
nullptr-0 added 1 commit 2022-11-20 17:50:34 +00:00
nullptr-0 requested review from jixunmoe 2022-11-20 18:45:45 +00:00
nullptr-0 added 1 commit 2022-11-20 21:01:00 +00:00
nullptr-0 added 1 commit 2022-11-20 21:16:23 +00:00
nullptr-0 added 1 commit 2022-11-21 17:55:10 +00:00
um-dev approved these changes 2022-11-21 19:55:49 +00:00
um-dev left a comment
Owner

看起来这些术语构建产物,添加到 .gitignore

  • src/KgmWasm/KgmWasm.js
  • src/KgmWasm/KgmWasm.wasm
  • src/KgmWasm/KgmWasmBundle.js
  • src/QmcWasm/QmcWasm.js
  • src/QmcWasm/QmcWasm.wasm
  • src/QmcWasm/QmcWasmBundle.js
看起来这些术语构建产物,添加到 .gitignore * src/KgmWasm/KgmWasm.js * src/KgmWasm/KgmWasm.wasm * src/KgmWasm/KgmWasmBundle.js * src/QmcWasm/QmcWasm.js * src/QmcWasm/QmcWasm.wasm * src/QmcWasm/QmcWasmBundle.js
um-dev requested review from um-dev 2022-11-21 19:55:56 +00:00
um-dev requested changes 2022-11-21 19:56:38 +00:00
um-dev left a comment
Owner

看起来这些术语构建产物,添加到 .gitignore

  • src/KgmWasm/KgmWasm.js
  • src/KgmWasm/KgmWasm.wasm
  • src/KgmWasm/KgmWasmBundle.js
  • src/QmcWasm/QmcWasm.js
  • src/QmcWasm/QmcWasm.wasm
  • src/QmcWasm/QmcWasmBundle.js
看起来这些术语构建产物,添加到 .gitignore * src/KgmWasm/KgmWasm.js * src/KgmWasm/KgmWasm.wasm * src/KgmWasm/KgmWasmBundle.js * src/QmcWasm/QmcWasm.js * src/QmcWasm/QmcWasm.wasm * src/QmcWasm/QmcWasmBundle.js
nullptr-0 added 1 commit 2022-11-21 22:40:57 +00:00
nullptr-0 requested review from um-dev 2022-11-21 22:41:43 +00:00
nullptr-0 added 1 commit 2022-11-21 23:00:02 +00:00
nullptr-0 added 1 commit 2022-11-23 20:40:14 +00:00
nullptr-0 added 1 commit 2022-11-23 20:47:01 +00:00
nullptr-0 added 1 commit 2022-11-23 20:55:26 +00:00
nullptr-0 added 1 commit 2022-11-23 20:59:53 +00:00
um-dev requested changes 2022-11-24 07:00:36 +00:00
@ -22,1 +22,4 @@
*.sw?
/src/KgmWasm/build
/src/KgmWasm/build
Owner

/src/KgmWasm/build -> /src/QmcWasm/build

`/src/KgmWasm/build` -> `/src/QmcWasm/build`
um-dev marked this conversation as resolved
@ -0,0 +192,4 @@
{
for (size_t i = 0; i < blobData.size(); i++) {
blobData[i] ^= 0xf4;
blobData[i] = ((blobData[i] & 0b0011_1111) << 2) | (blobData[i] >> 6); // rol 2
Owner

这里有语法错误,C++不支持分隔符
0b0011_1111 -> 0b00111111

这里有语法错误,C++不支持分隔符 `0b0011_1111` -> `0b00111111`
um-dev marked this conversation as resolved
um-dev force-pushed master from 83d0bcca75 to c8c4f8dfd6 2022-11-24 07:13:26 +00:00 Compare
um-dev requested review from um-dev 2022-11-24 07:14:19 +00:00
um-dev approved these changes 2022-11-24 07:14:38 +00:00
um-dev left a comment
Owner

LGTM;其他与 QmcWasm / KgmWasm 不相关的移动到 #9 跟踪处理

LGTM;其他与 QmcWasm / KgmWasm 不相关的移动到 https://git.unlock-music.dev/um/web/issues/9 跟踪处理
um-dev merged commit 4d3ef0ddaa into master 2022-11-24 07:32:59 +00:00
Sign in to join this conversation.
No description provided.