示例

QQ20251010-200612.png

服务器端安装

wget https://github.com/magic-akari/ncmc/releases/download/vX.Y.Z/ncmc-x86_64-unknown-linux-musl.tgz

或进入此开源项目下载对应服务器版本
magic-akari/ncmc

解压

tar -xzvf ncmc-x86_64-unknown-linux-musl.tgz

移动解压文件

sudo mv ncmc /usr/local/bin/ 
sudo chmod +x /usr/local/bin

验证安装

ncmc --version

调用

**本网站使用的是 Typecho,我们需要在默认模板下方新建一个PHP文件用于发布自定义页面,路径在宝塔面板此处:
/www/wwwroot/你的网页域名/usr/themes/default**

使用

需要在新建空白的PHP里面复制粘贴以下php代码

<?php
/**
 * Typecho 页面模板:NCM 转 MP3(拖拽上传+美化版)
 */
$this->need('header.php');
?>

<style>
.typecho-page-content {
    max-width: 600px;
    margin: 40px auto;
    padding: 30px;
    background: #f9f9f9;
    border-radius: 12px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.1);
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

/* 标题 */
.typecho-page-content h2 {
    text-align: center;
    margin-bottom: 25px;
    color: #333;
}

/* 上传区域 */
#drop-area {
    border: 2px dashed #4CAF50;
    border-radius: 12px;
    padding: 40px;
    text-align: center;
    cursor: pointer;
    transition: background 0.3s, border-color 0.3s;
    color: #666;
}

#drop-area.hover {
    background: #e8f5e9;
    border-color: #45a049;
}

#drop-area p {
    margin: 0;
    font-size: 16px;
}

/* 隐藏默认文件输入框 */
#fileElem {
    display: none;
}

/* 按钮 */
button {
    margin-top: 20px;
    padding: 12px;
    background: #4CAF50;
    color: white;
    border: none;
    border-radius: 6px;
    font-size: 16px;
    cursor: pointer;
    transition: 0.3s;
}

button:hover {
    background: #45a049;
}

/* 状态信息 */
#status {
    margin-top: 20px;
    padding: 15px;
    border-radius: 8px;
    background: #fff3cd;
    color: #856404;
    border: 1px solid #ffeeba;
}

#status a {
    color: #155724;
    font-weight: bold;
    text-decoration: none;
}

#status a:hover {
    text-decoration: underline;
}
</style>

<div class="typecho-page-content">
    <h2>NCM 文件转换 MP3(30 分钟有效)</h2>

    <form method="post" enctype="multipart/form-data" id="uploadForm">
        <div id="drop-area">
            <p>拖拽 NCM 文件到此处,或点击选择文件</p>
            <input type="file" name="ncmfile" id="fileElem" accept=".ncm" required>
            <button type="submit">上传并转换</button>
        </div>
    </form>

    <div id="status">
<?php
$uploadDir   = __DIR__ . '/uploads/';
$downloadDir = __DIR__ . '/downloads/';

foreach([$uploadDir, $downloadDir] as $dir){
    if(!is_dir($dir)) mkdir($dir, 0755, true);
}

if(!isset($_COOKIE['fingerprint'])){
    $fingerprint = bin2hex(random_bytes(16));
    setcookie('fingerprint', $fingerprint, time()+3600, "/");
} else {
    $fingerprint = $_COOKIE['fingerprint'];
}

// 自动清理超过 30 分钟的 MP3 文件
$files = glob($downloadDir . '*.mp3');
foreach($files as $f){
    if(time() - filemtime($f) > 30*60){
        @unlink($f);
    }
}

// 检查用户最近 30 分钟上传的 MP3 文件
$userFiles = glob($downloadDir . '*' . $fingerprint . '*.mp3');

// 按时间排序,最近上传的在前
usort($userFiles, function($a, $b){
    return filemtime($b) - filemtime($a);
});

if(!empty($userFiles)){
    echo "<strong>您最近 30 分钟转换的 MP3 文件:</strong><br><ul style='padding-left:20px'>";
    foreach($userFiles as $f){
        // 获取文件名显示给用户(去掉指纹和时间戳)
        $baseName = basename($f);
        // 移除 _fingerprint_timestamp 部分
        $displayName = preg_replace('/_[a-f0-9]{32}_\d+\.mp3$/', '.mp3', $baseName);

        $fileUrl = str_replace($_SERVER['DOCUMENT_ROOT'], '', $f);
        echo "<li><a href='$fileUrl' download>$displayName</a></li>";
    }
    echo "</ul>";
}


// 上传并转换
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['ncmfile'])){
    $file = $_FILES['ncmfile'];
    $filename = basename($file['name']);
    $filePath = $uploadDir . $filename;

    if(strtolower(pathinfo($filename, PATHINFO_EXTENSION)) !== 'ncm'){
        echo "只允许上传 .ncm 文件。";
        exit;
    }

    if(move_uploaded_file($file['tmp_name'], $filePath)){
        $timestamp = time();
        $outputFile = $downloadDir . pathinfo($filename, PATHINFO_FILENAME) . '_' . $fingerprint . '_' . $timestamp . '.mp3';

        $cmd = '/usr/local/bin/ncmc ' . escapeshellarg($filePath) . ' 2>&1';
        exec($cmd, $output, $returnVar);

        $mp3File = $uploadDir . pathinfo($filename, PATHINFO_FILENAME) . '.mp3';
        if($returnVar === 0 && file_exists($mp3File)){
            rename($mp3File, $outputFile);
            $fileUrl = str_replace($_SERVER['DOCUMENT_ROOT'], '', $outputFile);
            echo "转换成功!<a href='$fileUrl' download>点击下载 MP3</a>";
        } else {
            echo "转换失败,错误信息:<pre>" . implode("\n", $output) . "</pre>";
        }
    } else {
        echo "上传失败,请检查上传目录权限。";
    }
}
?>
    </div>
</div>

<script>
// 拖拽上传逻辑
let dropArea = document.getElementById('drop-area');
let fileInput = document.getElementById('fileElem');

['dragenter','dragover'].forEach(eventName => {
  dropArea.addEventListener(eventName, e => {
      e.preventDefault();
      e.stopPropagation();
      dropArea.classList.add('hover');
  }, false);
});

['dragleave','drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, e => {
      e.preventDefault();
      e.stopPropagation();
      dropArea.classList.remove('hover');
  }, false);
});

dropArea.addEventListener('drop', e => {
    let dt = e.dataTransfer;
    let files = dt.files;
    if(files.length){
        fileInput.files = files;
    }
});

dropArea.addEventListener('click', () => {
    fileInput.click();
});
</script>

<?php $this->need('footer.php'); ?>

来到Typecho管理页面选择:

  • 创建页面
  • 填写一个页面标题,比如“ncm转mp3”内容可不填写
  • 来到页面的右边,选择“自定义模板”发布即可**

    关于为什么没有前端解密

    因为没有找到相关前端解密的js,反正能用就行