Skip to content

Commit

Permalink
feat: fully migrate core function to @vincent-the-gamer/utils.
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-the-gamer committed Jan 25, 2024
1 parent 6ff73a5 commit 4cdeeb5
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 291 deletions.
55 changes: 32 additions & 23 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"vite": "^4.4.9"
},
"dependencies": {
"@vincent-the-gamer/utils": "^0.1.0",
"@vincent-the-gamer/utils": "^0.1.5",
"axios": "^1.5.0",
"svelte-spa-router": "^3.3.0"
}
Expand Down
17 changes: 0 additions & 17 deletions frontend/src/hooks/useCurrentPlatform.ts

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/lib/Main.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
} from "@/utils/initDirectories";
import axios from "@/utils/axios";
import { onMount } from "svelte";
import { detectBPM } from "@vincent-the-gamer/utils"
import { detectBPM } from "@vincent-the-gamer/utils/client"
import judgePath from "@/utils/judgePath";
import { link } from "svelte-spa-router";
Expand Down
20 changes: 10 additions & 10 deletions frontend/src/utils/initDirectories.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
import useCurrentPlatform from "@/hooks/useCurrentPlatform"
import { getCurrentPlatform } from "@vincent-the-gamer/utils"
import os from "os"

// init directorys
export function getNcmDir(){
const platform = useCurrentPlatform()
const platform = getCurrentPlatform()
if(localStorage.getItem("ncmDir")) return localStorage.getItem("ncmDir")
else{
if(platform === "win32" || platform === "win64"){
if(platform === "windows"){
return `C:\\Users\\Public\\ncm`
} else if(platform === "mac") {
} else if(platform === "macOS") {
return `/Users/Shared/ncm`
}
else return `/home/${os.userInfo().username}/Public/ncm`
}
}

export function getMp3OutDir(){
const platform = useCurrentPlatform()
const platform = getCurrentPlatform()
if(localStorage.getItem("mp3OutDir")) return localStorage.getItem("mp3OutDir")
else{
if(platform === "win32" || platform === "win64"){
if(platform === "windows" ){
return `C:\\Users\\Public\\mp3`
} else if(platform === "mac") {
} else if(platform === "macOS") {
return `/Users/Shared/mp3`
}
else return `/home/${os.userInfo().username}/Public/mp3`
}
}

export function getSongCoverOutDir(){
const platform = useCurrentPlatform()
const platform = getCurrentPlatform()
if(localStorage.getItem("songCoverOutDir")) return localStorage.getItem("songCoverOutDir")
else{
if(platform === "win32" || platform === "win64"){
if(platform === "windows"){
return `C:\\Users\\Public\\songcover`
} else if(platform === "mac") {
} else if(platform === "macOS") {
return `/Users/Shared/songcover`
}
else return `/home/${os.userInfo().username}/Public/songcover`
Expand Down
9 changes: 4 additions & 5 deletions frontend/src/utils/judgePath.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import useCurrentPlatform from "@/hooks/useCurrentPlatform"
import { getCurrentPlatform } from "@vincent-the-gamer/utils";

export default function judgePath(path: string): boolean{
const winDirRegex: RegExp = /^[A-Z]:\\(?:[^<>:"/\\|?*]+\\)*[^<>:"/\\|?*]+$/
const macOrLinuxRegex: RegExp = /^\/(?:[^/]+\/)*[^/]+$/

const currentPlatform = useCurrentPlatform();
const currentPlatform = getCurrentPlatform();
switch (currentPlatform) {
case "win32":
case "win64":
case "windows":
return winDirRegex.test(path)
case "mac":
case "macOS":
case "linux":
return macOrLinuxRegex.test(path)
default:
Expand Down
122 changes: 4 additions & 118 deletions ncm2mp3.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/**
* netease music .ncm audio to mp3
*/

const { ncm2mp3 } = require("@vincent-the-gamer/utils/server")

// @ts-ignore
const fs = require("fs")
const aes = require("aes-js")
// @ts-ignore
const path = require("path")

Expand Down Expand Up @@ -39,120 +41,4 @@ async function preCheck(ncmDir){
})
}

module.exports.ncm2mp3CustomDirectory = async (ncmDir, mp3OutDir, songCoverOutDir) => {
preCheck(ncmDir).then(success => {
fs.readdir(path.resolve(__dirname, ncmDir), function (err, files) {
files.forEach(v => {
const filePath = path.resolve(__dirname, ncmDir) + "/" + v

// 只对ncm后缀的文件进行操作
if( filePath.trim().endsWith(".ncm") ) {
const file = fs.readFileSync(filePath);
let globalOffset = 10;

const keyLength = file.readUInt32LE(10);
globalOffset += 4;

const keyData = Buffer.alloc(keyLength);

file.copy(keyData, 0, globalOffset, globalOffset + keyLength);
globalOffset += keyLength;

for (let i = 0; i < keyLength; i++) {
keyData[i] ^= 0x64;
}

const coreKey = new Uint8Array([0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57]);

const aesEcb = new aes.ModeOfOperation.ecb(coreKey);

const decodedKeyData = aes.padding.pkcs7.strip(aesEcb.decrypt(keyData));

const trimKeyData = decodedKeyData.slice(17);


const metaLength = file.readUInt32LE(globalOffset);
globalOffset += 4;

const metaData = Buffer.alloc(metaLength);
file.copy(metaData, 0, globalOffset, globalOffset + metaLength);
globalOffset += metaLength;
for (let i = 0; i < metaLength; i++) {
metaData[i] ^= 0x63;
}

const base64decode = Buffer.from(Buffer.from(metaData.slice(22)).toString('ascii'), 'base64');

const metaKey = new Uint8Array([0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28]);
const aseMeta = new aes.ModeOfOperation.ecb(metaKey);
const meatArray = aes.padding.pkcs7.strip(aseMeta.decrypt(base64decode));

const metaJson = Buffer.from(meatArray).toString('utf8');

const metaObject = JSON.parse(metaJson.substr(6));

// 读取 crc32 校验
file.readUInt32LE(globalOffset);
globalOffset += 4;
globalOffset += 5;
// 读取图像长度
const imageLength = file.readUInt32LE(globalOffset);
globalOffset += 4;

const imageBuffer = Buffer.alloc(imageLength);
file.copy(imageBuffer, 0, globalOffset, globalOffset + imageLength);
globalOffset += imageLength;
// 写入图像文件
fs.writeFileSync(path.resolve(__dirname, songCoverOutDir) + "/" + v.replace(/.ncm/, '') + '.jpg', imageBuffer);

function buildKeyBox(key) {
const keyLength = key.length;
const box = Buffer.alloc(256);

for (let i = 0; i < 256; i++) {
box[i] = i;
}

let swap = 0;
let c = 0;
let lastByte = 0;
let keyOffset = 0;

for (let i = 0; i < 256; ++i) {
swap = box[i];
c = ((swap + lastByte + key[keyOffset++]) & 0xff);
if (keyOffset >= keyLength) {
keyOffset = 0;
}
box[i] = box[c];
box[c] = swap;
lastByte = c;
}

return box;
}

const box = buildKeyBox(trimKeyData);

let n = 0x8000;
let fmusic = [];
while (n > 1) {
const buffer = Buffer.alloc(n);
n = file.copy(buffer, 0, globalOffset, globalOffset + n);
globalOffset += n;

for (let i = 0; i < n; i++) {
let j = (i + 1) & 0xff;
buffer[i] ^= box[(box[j] + box[(box[j] + j) & 0xff]) & 0xff];
}
// @ts-ignore
fmusic.push(buffer);
}
fs.writeFileSync(path.resolve(__dirname, mp3OutDir) + "/" + v.replace(/.ncm/, '.mp3'), Buffer.concat(fmusic));
}
})
})
}, err => {
console.log(err)
})
}
module.exports.ncm2mp3CustomDirectory = ncm2mp3
Loading

0 comments on commit 4cdeeb5

Please sign in to comment.