forked from um/web
Merge pull request #207 from jixunmoe/feature/qmcv2-wasm
WIP: 实验 qmc2-crypto 包
This commit is contained in:
commit
2a23845714
246
package-lock.json
generated
246
package-lock.json
generated
@ -7,9 +7,11 @@
|
||||
"": {
|
||||
"name": "unlock-music",
|
||||
"version": "v1.9.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.16.5",
|
||||
"@jixun/qmc2-crypto": "^0.0.5-R4",
|
||||
"base64-js": "^1.5.1",
|
||||
"browser-id3-writer": "^4.4.0",
|
||||
"core-js": "^3.16.0",
|
||||
@ -33,6 +35,7 @@
|
||||
"@vue/cli-service": "^4.5.13",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"jest": "^27.4.5",
|
||||
"patch-package": "^6.4.7",
|
||||
"sass": "^1.38.1",
|
||||
"sass-loader": "^10.2.0",
|
||||
"semver": "^7.3.5",
|
||||
@ -2980,6 +2983,11 @@
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@jixun/qmc2-crypto": {
|
||||
"version": "0.0.5-R4",
|
||||
"resolved": "https://registry.npmjs.org/@jixun/qmc2-crypto/-/qmc2-crypto-0.0.5-R4.tgz",
|
||||
"integrity": "sha512-4xGClhxMd1BL7UjE+fZr+a4GYkfEjwU216WZ89ouANwR8Q27PhQrra+msEvM4J/mBBCjv/x/eIcS67XBasHKUQ=="
|
||||
},
|
||||
"node_modules/@mrmlnc/readdir-enhanced": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||
@ -4176,6 +4184,12 @@
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@yarnpkg/lockfile": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
|
||||
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/abab": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
|
||||
@ -8563,6 +8577,28 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/find-yarn-workspace-root": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
|
||||
"integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"micromatch": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/find-yarn-workspace-root/node_modules/micromatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/flush-write-stream": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
|
||||
@ -12945,6 +12981,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/klaw-sync": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
@ -14489,6 +14534,15 @@
|
||||
"integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
@ -14692,6 +14746,76 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package": {
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz",
|
||||
"integrity": "sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"find-yarn-workspace-root": "^2.0.0",
|
||||
"fs-extra": "^7.0.1",
|
||||
"is-ci": "^2.0.0",
|
||||
"klaw-sync": "^6.0.0",
|
||||
"minimist": "^1.2.0",
|
||||
"open": "^7.4.2",
|
||||
"rimraf": "^2.6.3",
|
||||
"semver": "^5.6.0",
|
||||
"slash": "^2.0.0",
|
||||
"tmp": "^0.0.33"
|
||||
},
|
||||
"bin": {
|
||||
"patch-package": "index.js"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">5"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/ci-info": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/patch-package/node_modules/is-ci": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
|
||||
"integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ci-info": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"is-ci": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/open": {
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
|
||||
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-docker": "^2.0.0",
|
||||
"is-wsl": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
|
||||
@ -18194,6 +18318,18 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tmpl": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||
@ -23019,6 +23155,11 @@
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
}
|
||||
},
|
||||
"@jixun/qmc2-crypto": {
|
||||
"version": "0.0.5-R4",
|
||||
"resolved": "https://registry.npmjs.org/@jixun/qmc2-crypto/-/qmc2-crypto-0.0.5-R4.tgz",
|
||||
"integrity": "sha512-4xGClhxMd1BL7UjE+fZr+a4GYkfEjwU216WZ89ouANwR8Q27PhQrra+msEvM4J/mBBCjv/x/eIcS67XBasHKUQ=="
|
||||
},
|
||||
"@mrmlnc/readdir-enhanced": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||
@ -24069,6 +24210,12 @@
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@yarnpkg/lockfile": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
|
||||
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"abab": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
|
||||
@ -27597,6 +27744,27 @@
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"find-yarn-workspace-root": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
|
||||
"integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromatch": "^4.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"micromatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.2.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flush-write-stream": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
|
||||
@ -30882,6 +31050,15 @@
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"dev": true
|
||||
},
|
||||
"klaw-sync": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
@ -32143,6 +32320,12 @@
|
||||
"integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
|
||||
"dev": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true
|
||||
},
|
||||
"p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
@ -32314,6 +32497,60 @@
|
||||
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
|
||||
"dev": true
|
||||
},
|
||||
"patch-package": {
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz",
|
||||
"integrity": "sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"find-yarn-workspace-root": "^2.0.0",
|
||||
"fs-extra": "^7.0.1",
|
||||
"is-ci": "^2.0.0",
|
||||
"klaw-sync": "^6.0.0",
|
||||
"minimist": "^1.2.0",
|
||||
"open": "^7.4.2",
|
||||
"rimraf": "^2.6.3",
|
||||
"semver": "^5.6.0",
|
||||
"slash": "^2.0.0",
|
||||
"tmp": "^0.0.33"
|
||||
},
|
||||
"dependencies": {
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-ci": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
|
||||
"integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ci-info": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"open": {
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
|
||||
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-docker": "^2.0.0",
|
||||
"is-wsl": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"path-browserify": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
|
||||
@ -35216,6 +35453,15 @@
|
||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz",
|
||||
"integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA=="
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"tmpl": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"postinstall": "patch-package",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test": "jest",
|
||||
@ -18,6 +19,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.16.5",
|
||||
"@jixun/qmc2-crypto": "^0.0.5-R4",
|
||||
"base64-js": "^1.5.1",
|
||||
"browser-id3-writer": "^4.4.0",
|
||||
"core-js": "^3.16.0",
|
||||
@ -41,6 +43,7 @@
|
||||
"@vue/cli-service": "^4.5.13",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"jest": "^27.4.5",
|
||||
"patch-package": "^6.4.7",
|
||||
"sass": "^1.38.1",
|
||||
"sass-loader": "^10.2.0",
|
||||
"semver": "^7.3.5",
|
||||
|
11
patches/threads+1.7.0.patch
Normal file
11
patches/threads+1.7.0.patch
Normal file
@ -0,0 +1,11 @@
|
||||
diff --git a/node_modules/threads/worker.mjs b/node_modules/threads/worker.mjs
|
||||
index c53ac7d..619007b 100644
|
||||
--- a/node_modules/threads/worker.mjs
|
||||
+++ b/node_modules/threads/worker.mjs
|
||||
@@ -1,4 +1,5 @@
|
||||
-import WorkerContext from "./dist/worker/index.js"
|
||||
+// Workaround: use of import seems to break minifier.
|
||||
+const WorkerContext = require("./dist/worker/index.js")
|
||||
|
||||
export const expose = WorkerContext.expose
|
||||
export const registerSerializer = WorkerContext.registerSerializer
|
@ -38,8 +38,10 @@ export async function CommonDecrypt(file: FileInfo): Promise<DecryptResult> {
|
||||
case "tkm"://QQ Music Accompaniment M4a
|
||||
case "bkcmp3"://Moo Music Mp3
|
||||
case "bkcflac"://Moo Music Flac
|
||||
case "mflac"://QQ Music Desktop Flac
|
||||
case "mgg": //QQ Music Desktop Ogg
|
||||
case "mflac"://QQ Music New Flac
|
||||
case "mflac0"://QQ Music New Flac
|
||||
case "mgg": //QQ Music New Ogg
|
||||
case "mgg1": //QQ Music New Ogg
|
||||
case "666c6163"://QQ Music Weiyun Flac
|
||||
case "6d7033"://QQ Music Weiyun Mp3
|
||||
case "6f6767"://QQ Music Weiyun Ogg
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {QmcMask, QmcMaskDetectMflac, QmcMaskDetectMgg, QmcMaskGetDefault} from "./qmcMask";
|
||||
import {QmcMask, QmcMaskGetDefault} from "./qmcMask";
|
||||
import {toByteArray as Base64Decode} from 'base64-js'
|
||||
import {
|
||||
AudioMimeType,
|
||||
@ -9,6 +9,7 @@ import {
|
||||
SniffAudioExt, WriteMetaToFlac, WriteMetaToMp3
|
||||
} from "@/decrypt/utils";
|
||||
import {parseBlob as metaParseBlob} from "music-metadata-browser";
|
||||
import {DecryptQMCv2} from "./qmcv2";
|
||||
|
||||
|
||||
import iconv from "iconv-lite";
|
||||
@ -17,51 +18,57 @@ import {queryAlbumCover, queryKeyInfo, reportKeyUsage} from "@/utils/api";
|
||||
|
||||
interface Handler {
|
||||
ext: string
|
||||
detect: boolean
|
||||
|
||||
handler(data?: Uint8Array): QmcMask | undefined
|
||||
version: number
|
||||
}
|
||||
|
||||
export const HandlerMap: { [key: string]: Handler } = {
|
||||
"mgg": {handler: QmcMaskDetectMgg, ext: "ogg", detect: true},
|
||||
"mflac": {handler: QmcMaskDetectMflac, ext: "flac", detect: true},
|
||||
"mgg.cache": {handler: QmcMaskDetectMgg, ext: "ogg", detect: false},
|
||||
"mflac.cache": {handler: QmcMaskDetectMflac, ext: "flac", detect: false},
|
||||
"qmc0": {handler: QmcMaskGetDefault, ext: "mp3", detect: false},
|
||||
"qmc2": {handler: QmcMaskGetDefault, ext: "ogg", detect: false},
|
||||
"qmc3": {handler: QmcMaskGetDefault, ext: "mp3", detect: false},
|
||||
"qmcogg": {handler: QmcMaskGetDefault, ext: "ogg", detect: false},
|
||||
"qmcflac": {handler: QmcMaskGetDefault, ext: "flac", detect: false},
|
||||
"bkcmp3": {handler: QmcMaskGetDefault, ext: "mp3", detect: false},
|
||||
"bkcflac": {handler: QmcMaskGetDefault, ext: "flac", detect: false},
|
||||
"tkm": {handler: QmcMaskGetDefault, ext: "m4a", detect: false},
|
||||
"666c6163": {handler: QmcMaskGetDefault, ext: "flac", detect: false},
|
||||
"6d7033": {handler: QmcMaskGetDefault, ext: "mp3", detect: false},
|
||||
"6f6767": {handler: QmcMaskGetDefault, ext: "ogg", detect: false},
|
||||
"6d3461": {handler: QmcMaskGetDefault, ext: "m4a", detect: false},
|
||||
"776176": {handler: QmcMaskGetDefault, ext: "wav", detect: false}
|
||||
"mgg": {ext: "ogg", version: 2},
|
||||
"mgg1": {ext: "ogg", version: 2},
|
||||
"mflac": {ext: "flac", version: 2},
|
||||
"mflac0": {ext: "flac", version: 2},
|
||||
|
||||
// qmcflac / qmcogg:
|
||||
// 有可能是 v2 加密但混用同一个后缀名。
|
||||
"qmcflac": {ext: "flac", version: 2},
|
||||
"qmcogg": {ext: "ogg", version: 2},
|
||||
|
||||
"qmc0": {ext: "mp3", version: 1},
|
||||
"qmc2": {ext: "ogg", version: 1},
|
||||
"qmc3": {ext: "mp3", version: 1},
|
||||
"bkcmp3": {ext: "mp3", version: 1},
|
||||
"bkcflac": {ext: "flac", version: 1},
|
||||
"tkm": {ext: "m4a", version: 1},
|
||||
"666c6163": {ext: "flac", version: 1},
|
||||
"6d7033": {ext: "mp3", version: 1},
|
||||
"6f6767": {ext: "ogg", version: 1},
|
||||
"6d3461": {ext: "m4a", version: 1},
|
||||
"776176": {ext: "wav", version: 1}
|
||||
};
|
||||
|
||||
export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise<DecryptResult> {
|
||||
if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`;
|
||||
const handler = HandlerMap[raw_ext];
|
||||
let { version } = handler;
|
||||
|
||||
const fileData = new Uint8Array(await GetArrayBuffer(file));
|
||||
let audioData, seed, keyData;
|
||||
if (handler.detect) {
|
||||
const keyLen = new DataView(fileData.slice(fileData.length - 4).buffer).getUint32(0, true)
|
||||
const keyPos = fileData.length - 4 - keyLen;
|
||||
audioData = fileData.slice(0, keyPos);
|
||||
seed = handler.handler(audioData);
|
||||
keyData = fileData.slice(keyPos, keyPos + keyLen);
|
||||
if (!seed) seed = await queryKey(keyData, raw_filename, raw_ext);
|
||||
if (!seed) throw raw_ext + "格式仅提供实验性支持";
|
||||
} else {
|
||||
audioData = fileData;
|
||||
seed = handler.handler(audioData) as QmcMask;
|
||||
if (!seed) throw raw_ext + "格式仅提供实验性支持";
|
||||
const fileBuffer = await GetArrayBuffer(file);
|
||||
let musicDecoded: Uint8Array|undefined;
|
||||
|
||||
if (version === 2) {
|
||||
const v2Decrypted = await DecryptQMCv2(fileBuffer);
|
||||
// 如果 v2 检测失败,降级到 v1 再尝试一次
|
||||
if (v2Decrypted) {
|
||||
musicDecoded = v2Decrypted;
|
||||
} else {
|
||||
version = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (version === 1) {
|
||||
const seed = QmcMaskGetDefault();
|
||||
musicDecoded = seed.Decrypt(new Uint8Array(fileBuffer));
|
||||
} else if (!musicDecoded) {
|
||||
throw new Error(`解密失败: ${raw_ext}`);
|
||||
}
|
||||
let musicDecoded = seed.Decrypt(audioData);
|
||||
|
||||
const ext = SniffAudioExt(musicDecoded, handler.ext);
|
||||
const mime = AudioMimeType[ext];
|
||||
@ -80,8 +87,6 @@ export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string)
|
||||
}
|
||||
|
||||
const info = GetMetaFromFile(raw_filename, musicMeta.common.title, musicMeta.common.artist)
|
||||
if (keyData) reportKeyUsage(keyData, seed.getMatrix128(),
|
||||
raw_filename, raw_ext, info.title, info.artist, musicMeta.common.album).then().catch();
|
||||
|
||||
let imgUrl = GetCoverFromFile(musicMeta);
|
||||
if (!imgUrl) {
|
||||
|
@ -1,31 +1,3 @@
|
||||
import {BytesHasPrefix, FLAC_HEADER, OGG_HEADER} from "@/decrypt/utils";
|
||||
|
||||
const QMOggPublicHeader1 = [
|
||||
0x4f, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x1e, 0x01, 0x76, 0x6f, 0x72,
|
||||
0x62, 0x69, 0x73, 0x00, 0x00, 0x00, 0x00, 0x02, 0x44, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xee, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x4f, 0x67, 0x67, 0x53, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff];
|
||||
const QMOggPublicHeader2 = [
|
||||
0x03, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x2c, 0x00, 0x00, 0x00, 0x58, 0x69, 0x70, 0x68, 0x2e,
|
||||
0x4f, 0x72, 0x67, 0x20, 0x6c, 0x69, 0x62, 0x56, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x20, 0x49, 0x20,
|
||||
0x32, 0x30, 0x31, 0x35, 0x30, 0x31, 0x30, 0x35, 0x20, 0x28, 0xe2, 0x9b, 0x84, 0xe2, 0x9b, 0x84,
|
||||
0xe2, 0x9b, 0x84, 0xe2, 0x9b, 0x84, 0x29, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x54,
|
||||
0x49, 0x54, 0x4c, 0x45, 0x3d];
|
||||
const QMOggPublicConf1 = [
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
|
||||
0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 6, 3, 3, 3, 3, 6, 6, 6, 6,
|
||||
3, 3, 3, 3, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9,
|
||||
0, 0, 0, 0];
|
||||
const QMOggPublicConf2 = [
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 0, 1, 3, 3, 0, 1, 3, 3, 3,
|
||||
3, 3, 3, 3, 3];
|
||||
const QMCDefaultMaskMatrix = [
|
||||
0xde, 0x51, 0xfa, 0xc3, 0x4a, 0xd6, 0xca, 0x90,
|
||||
0x7e, 0x67, 0x5e, 0xf7, 0xd5, 0x52, 0x84, 0xd8,
|
||||
@ -34,7 +6,6 @@ const QMCDefaultMaskMatrix = [
|
||||
0x1d, 0x3f, 0x5b, 0xf0, 0x13, 0x0e, 0x09, 0x3d,
|
||||
0xf9, 0xbc, 0x00, 0x11];
|
||||
|
||||
|
||||
const AllMapping: number[][] = [];
|
||||
const Mask128to44: number[] = [];
|
||||
|
||||
@ -57,7 +28,6 @@ const Mask128to44: number[] = [];
|
||||
})
|
||||
})();
|
||||
|
||||
|
||||
export class QmcMask {
|
||||
private readonly Matrix128: number[];
|
||||
|
||||
@ -126,81 +96,3 @@ export class QmcMask {
|
||||
export function QmcMaskGetDefault() {
|
||||
return new QmcMask(QMCDefaultMaskMatrix)
|
||||
}
|
||||
|
||||
export function QmcMaskDetectMflac(data: Uint8Array) {
|
||||
let search_len = Math.min(0x8000, data.length)
|
||||
for (let block_idx = 0; block_idx < search_len; block_idx += 128) {
|
||||
try {
|
||||
let mask = new QmcMask(data.slice(block_idx, block_idx + 128));
|
||||
if (BytesHasPrefix(mask.Decrypt(data.slice(0, FLAC_HEADER.length)), FLAC_HEADER)) {
|
||||
return mask
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
export function QmcMaskDetectMgg(data: Uint8Array) {
|
||||
if (data.length < 0x100) return
|
||||
let matrixConfidence: { [key: number]: { [key: number]: number } } = {};
|
||||
for (let i = 0; i < 44; i++) matrixConfidence[i] = {};
|
||||
|
||||
const page2 = data[0x54] ^ data[0xC] ^ QMOggPublicHeader1[0xC];
|
||||
const spHeader = QmcGenerateOggHeader(page2)
|
||||
const spConf = QmcGenerateOggConf(page2)
|
||||
|
||||
for (let idx128 = 0; idx128 < spHeader.length; idx128++) {
|
||||
if (spConf[idx128] === 0) continue;
|
||||
let idx44 = Mask128to44[idx128 % 128];
|
||||
let _m = data[idx128] ^ spHeader[idx128]
|
||||
let confidence = spConf[idx128];
|
||||
if (_m in matrixConfidence[idx44]) {
|
||||
matrixConfidence[idx44][_m] += confidence
|
||||
} else {
|
||||
matrixConfidence[idx44][_m] = confidence
|
||||
}
|
||||
}
|
||||
let matrix = [];
|
||||
try {
|
||||
for (let i = 0; i < 44; i++)
|
||||
matrix[i] = calcMaskFromConfidence(matrixConfidence[i]);
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
const mask = new QmcMask(matrix);
|
||||
if (BytesHasPrefix(mask.Decrypt(data.slice(0, OGG_HEADER.length)), OGG_HEADER)) {
|
||||
return mask
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
function calcMaskFromConfidence(confidence: { [key: number]: number }) {
|
||||
const count = Object.keys(confidence).length
|
||||
if (count === 0) throw "can not match at least one key";
|
||||
if (count > 1) console.warn("There are 2 potential value for the mask!")
|
||||
let result = ""
|
||||
let conf = 0
|
||||
for (let idx in confidence) {
|
||||
if (confidence[idx] > conf) {
|
||||
result = idx;
|
||||
conf = confidence[idx];
|
||||
}
|
||||
}
|
||||
return Number(result)
|
||||
}
|
||||
|
||||
function QmcGenerateOggHeader(page2: number) {
|
||||
let spec = [page2, 0xFF]
|
||||
for (let i = 2; i < page2; i++) spec.push(0xFF)
|
||||
spec.push(0xFF)
|
||||
return QMOggPublicHeader1.concat(spec, QMOggPublicHeader2)
|
||||
}
|
||||
|
||||
function QmcGenerateOggConf(page2: number) {
|
||||
let specConf = [6, 0]
|
||||
for (let i = 2; i < page2; i++) specConf.push(4)
|
||||
specConf.push(0)
|
||||
return QMOggPublicConf1.concat(specConf, QMOggPublicConf2)
|
||||
}
|
||||
|
103
src/decrypt/qmcv2.ts
Normal file
103
src/decrypt/qmcv2.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import QMCCryptoModule from '@jixun/qmc2-crypto/QMC2-wasm-bundle';
|
||||
|
||||
// 检测文件末端使用的缓冲区大小
|
||||
const DETECTION_SIZE = 40;
|
||||
|
||||
// 每次处理 2M 的数据
|
||||
const DECRYPTION_BUF_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
function MergeUint8Array(array: Uint8Array[]): Uint8Array {
|
||||
let length = 0;
|
||||
array.forEach(item => {
|
||||
length += item.length;
|
||||
});
|
||||
|
||||
let mergedArray = new Uint8Array(length);
|
||||
let offset = 0;
|
||||
array.forEach(item => {
|
||||
mergedArray.set(item, offset);
|
||||
offset += item.length;
|
||||
});
|
||||
|
||||
return mergedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密一个 QMC2 加密的文件。
|
||||
*
|
||||
* 如果检测并解密成功,返回解密后的 Uint8Array 数据。
|
||||
* @param {ArrayBuffer} mggBlob 读入的文件 Blob
|
||||
* @param {string} name 文件名
|
||||
* @return {Promise<Uint8Array|false>}
|
||||
*/
|
||||
export async function DecryptQMCv2(mggBlob: ArrayBuffer) {
|
||||
// 初始化模组
|
||||
const QMCCrypto = await QMCCryptoModule();
|
||||
|
||||
// 申请内存块,并文件末端数据到 WASM 的内存堆
|
||||
const detectionBuf = new Uint8Array(mggBlob.slice(-DETECTION_SIZE));
|
||||
const pDetectionBuf = QMCCrypto._malloc(detectionBuf.length);
|
||||
QMCCrypto.writeArrayToMemory(detectionBuf, pDetectionBuf);
|
||||
|
||||
// 检测结果内存块
|
||||
const pDetectionResult = QMCCrypto._malloc(QMCCrypto.sizeof_qmc_detection());
|
||||
|
||||
// 进行检测
|
||||
const detectOK = QMCCrypto.detectKeyEndPosition(
|
||||
pDetectionResult,
|
||||
pDetectionBuf,
|
||||
detectionBuf.length
|
||||
);
|
||||
|
||||
// 提取结构体内容:
|
||||
// (pos: i32; len: i32; error: char[??])
|
||||
const position = QMCCrypto.getValue(pDetectionResult, "i32");
|
||||
const len = QMCCrypto.getValue(pDetectionResult + 4, "i32");
|
||||
|
||||
// 释放内存
|
||||
QMCCrypto._free(pDetectionBuf);
|
||||
QMCCrypto._free(pDetectionResult);
|
||||
|
||||
if (!detectOK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算解密后文件的大小。
|
||||
// 之前得到的 position 为相对当前检测数据起点的偏移。
|
||||
const decryptedSize = mggBlob.byteLength - DETECTION_SIZE + position;
|
||||
|
||||
// 提取嵌入到文件的 EKey
|
||||
const ekey = new Uint8Array(
|
||||
mggBlob.slice(decryptedSize, decryptedSize + len)
|
||||
);
|
||||
|
||||
// 解码 UTF-8 数据到 string
|
||||
const decoder = new TextDecoder();
|
||||
const ekey_b64 = decoder.decode(ekey);
|
||||
|
||||
// 初始化加密与缓冲区
|
||||
const hCrypto = QMCCrypto.createInstWidthEKey(ekey_b64);
|
||||
const buf = QMCCrypto._malloc(DECRYPTION_BUF_SIZE);
|
||||
|
||||
const decryptedParts = [];
|
||||
let offset = 0;
|
||||
let bytesToDecrypt = decryptedSize;
|
||||
while (bytesToDecrypt > 0) {
|
||||
const blockSize = Math.min(bytesToDecrypt, DECRYPTION_BUF_SIZE);
|
||||
|
||||
// 解密一些片段
|
||||
const blockData = new Uint8Array(
|
||||
mggBlob.slice(offset, offset + blockSize)
|
||||
);
|
||||
QMCCrypto.writeArrayToMemory(blockData, buf);
|
||||
QMCCrypto.decryptStream(hCrypto, buf, offset, blockSize);
|
||||
decryptedParts.push(QMCCrypto.HEAPU8.slice(buf, buf + blockSize));
|
||||
|
||||
offset += blockSize;
|
||||
bytesToDecrypt -= blockSize;
|
||||
}
|
||||
QMCCrypto._free(buf);
|
||||
hCrypto.delete();
|
||||
|
||||
return MergeUint8Array(decryptedParts);
|
||||
}
|
Loading…
Reference in New Issue
Block a user