taurusxin / ncmdump

转换网易云音乐 ncm 到 mp3 / flac. Convert Netease Cloud Music ncm files to mp3/flac files.
MIT License
1.04k stars 168 forks source link

是否可以支持指定输出目录 #7

Closed sciencekiller closed 8 months ago

sciencekiller commented 9 months ago

现在版本好像是只能输出到原目录,能不能加一个指定参数输出目录,这样复制的时候就不用很麻烦的搜索后缀复制。如果可以,还是麻烦把dll编译一下,用法的话就只用说一下在哪里指定路径,谢谢

Buer-Nahida commented 8 months ago

一个小解决方案:可以这样复制

cp *.mp3 /path/to/music/dir

或者可以这样:

mv *.ncm /path/to/dir
ncmdump -d /path/to/dir
cp /path/to/dir/*.mp3 ./
sciencekiller commented 8 months ago

这样可以在一定程度上解决问题,但它的问题就是会存在两份MP3文件。而我正试着将多余的一份删掉,可是作者似乎忘记加入了销毁占用的部分,以至于我在调用过Dump和FixMetaData方法后,转换文件将一直被占用直到程序结束。我无法删除或移动文件,因此,几乎无法解决这个两份文件的问题,除非作者可以将销毁对象的代码加入(我是学C#的,不会改C++代码)。作者大大改一下吧! Screenshot 2024-02-07 112206 Screenshot 2024-02-07 112216

taurusxin commented 8 months ago

年底比较忙,要年后加feature了

sciencekiller commented 8 months ago

作者是否可以提供一下编译出dll的方法教程呢?我可以尝试自行添加这个功能并提交

taurusxin commented 8 months ago

作者是否可以提供一下编译出dll的方法教程呢?我可以尝试自行添加这个功能并提交

编译C#和其它语言通用dll需要覆写一些方法,稍微有点麻烦,我看看今天能不能发布一版吧

sciencekiller commented 8 months ago

我认为在这个函数

void NeteaseCrypt::Dump() {
    mDumpFilepath = mFilepath;

    std::vector<unsigned char> buffer(0x8000);

    std::ofstream output;

    while (!mFile.eof()) {
        int n = read((char*)buffer.data(), buffer.size());

        for (int i = 0; i < n; i++) {
            int j = (i + 1) & 0xff;
            buffer[i] ^= mKeyBox[(mKeyBox[j] + mKeyBox[(mKeyBox[j] + j) & 0xff]) & 0xff];
        }

        if (!output.is_open()) {
            // identify format
            // ID3 format mp3
            if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x33) {
                mDumpFilepath.replace_extension(".mp3");
                mFormat = NeteaseCrypt::MP3;
            } else {
                mDumpFilepath.replace_extension(".flac");
                mFormat = NeteaseCrypt::FLAC;
            }

            output.open(mDumpFilepath, output.out | output.binary);
        }

        output.write((char*)buffer.data(), n);
    }

    output.flush();
    output.close();
}

可以添加一个Dump重载,传入目标目录,截取mFilepath的文件名部分,拼接在目标目录后,赋值给mDumpFilepath

sciencekiller commented 8 months ago

例如这样,应该是可行的(没有安装C++运行环境,无法测试)

void NeteaseCrypt::Dump(string targetFolder) {
    string filename=std::filesystem::path(mFilepath).filename().string();
    string destFilename=std::filesystem::path(targetFolder)/filename;
    mDumpFilepath = destFilename.string();

    std::vector<unsigned char> buffer(0x8000);

    std::ofstream output;

    while (!mFile.eof()) {
        int n = read((char*)buffer.data(), buffer.size());

        for (int i = 0; i < n; i++) {
            int j = (i + 1) & 0xff;
            buffer[i] ^= mKeyBox[(mKeyBox[j] + mKeyBox[(mKeyBox[j] + j) & 0xff]) & 0xff];
        }

        if (!output.is_open()) {
            // identify format
            // ID3 format mp3
            if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x33) {
                mDumpFilepath.replace_extension(".mp3");
                mFormat = NeteaseCrypt::MP3;
            } else {
                mDumpFilepath.replace_extension(".flac");
                mFormat = NeteaseCrypt::FLAC;
            }

            output.open(mDumpFilepath, output.out | output.binary);
        }

        output.write((char*)buffer.data(), n);
    }

    output.flush();
    output.close();
}
taurusxin commented 8 months ago

已经修复调用 FixMetadata 后文件依然被占用的问题,dll文件发布在1.2.1 的 release,请前往下载。 至于添加输出目录功能,暂时没有必要,可以自行编程移动文件。

解决过程: 封装成dll后并供其它语言调用时,TagLib File对象依旧存在于内存中导致没有析构,文件被占用,因为调用它的程序依旧在运行,将 File 对象改成智能指针后就行了。