美文网首页
开源小工具 酷狗、网易音乐缓存文件转mp3工具

开源小工具 酷狗、网易音乐缓存文件转mp3工具

作者: JadePeng | 来源:发表于2018-03-29 20:29 被阅读0次

    发布一个开源小工具,支持将酷狗和网易云音乐的缓存文件转码为MP3文件。

    以前写过kgtemp文件转mp3工具,正好当前又有网易云音乐缓存文件需求,因此就在原来小工具的基础上做了一点修改,增加了对网易云音乐的支持,并简单调整了下代码结构,方便后续增加其他音乐软件的支持。

    工具使用介绍

    下载程序(点击下载),然后启动程序,

    enter description hereenter description here
    • 首先,设置输入目录,也就是解密后的文件存放在哪里
    • 然后将酷狗或者网易的缓存文件 or 整个文件夹,拖入到程序即可
    转码中转码中

    打开转码结果目录,可以看到转码后的结果

    转码结果转码结果

    缓存目录如何找

    网易云音乐的缓存目录

    打开设置 -- 下载设置 - 缓存目录就是了

    enter description hereenter description here

    酷狗缓存目录

    如图,在设置--下载设置里

    enter description hereenter description here

    工具代码简要说明

    类图

    enter description hereenter description here

    ICacheDecrypt

    我们定义一个解码接口ICacheDecrypt,实现将缓存文件字节流转换为mp3字节流。

     /// <summary>
        /// 解密接口
        /// </summary>
        public interface ICacheDecrypt
        {
    
            string AcceptableExtension
            {
                get;
            }
    
            bool isAcceptable(string cacheFile);
    
            /// <summary>
            /// 解密文件
            /// </summary>
            /// <param name="cacheFile">缓存文件</param>
            /// <returns>解密后二进制数据</returns>
            byte[] Decrypt(string cacheFile);
    
            /// <summary>
            /// 解密文件
            /// </summary>
            /// <param name="cacheFileData">缓存文件数据</param>
            /// <returns></returns>
            byte[] Decrypt(byte[] cacheFileData);
    
            /// <summary>
            /// 解密文件
            /// </summary>
            /// <param name="cacheFile">cache文件</param>
            /// <param name="decodedFile">解密后文件</param>
            void Decrypt(string cacheFile,string decodedFile);
    
        }
    

    BaseCacheDecrypt

    然后,实现一个默认的抽象类BaseCacheDecrypt,实现一些公共的东西,具体的转码工作让子类去实现,比如网易和酷狗可以分别建一个子类。

    public abstract class BaseCacheDecrypt : ICacheDecrypt
        {
    
            protected string currentCacheFile;
    
            public abstract string AcceptableExtension
            {
                get;
            }
    
            public abstract byte[] Decrypt(byte[] cacheFileData);
    
            public byte[] Decrypt(string cacheFile)
            {
                currentCacheFile = cacheFile;
                return Decrypt(File.ReadAllBytes(cacheFile));
            }
    
            public void Decrypt(string cacheFile, string decodedFile)
            {
                File.WriteAllBytes(decodedFile, Decrypt(cacheFile));
            }
    
            public  bool isAcceptable(string cacheFile)
            {
                return cacheFile.EndsWith(AcceptableExtension);
            }
        }
    

    NetMusicCacheDecrypt

    然后,分别实现酷狗和网易云音乐的解码工作,酷狗的上次已经写了如何解码,这里只贴网易的,解码很简单,异或0xa3就可以了。网易音乐在测试时发现好多mp3没有ID3信息,经过观察发现缓存文件名里包含歌曲的id信息,因此可以根据这个id信息去抓取歌曲网页,解析出歌手和歌曲名称,然后写入到ID3里,这里ID3的读写采用了GitHub上的一个开源库

    
        /// <summary>
        /// 网易云缓存解密
        /// </summary>
        public class NetMusicCacheDecrypt : BaseCacheDecrypt
        {
            public override string AcceptableExtension
            {
                get
                {
                    return ".uc";
                }
            }
    
            string cut(string str,string start,string end)
            {
                var startIndex = str.IndexOf(start);
                if (startIndex == -1)
                {
                    return "";
                }
                startIndex += start.Length;
                var endIndex = str.IndexOf(end, startIndex);
                if (endIndex == -1)
                {
                    return "";
                }
                return str.Substring(startIndex, endIndex - startIndex);
            }
    
            public override byte[] Decrypt(byte[] cacheFileData)
            {         
                for (var i = 0; i < cacheFileData.Length; i++)
                {
                    // 异或0xa3
                    cacheFileData[i] ^= 0xa3;
                }
    
                var fileName = new FileInfo(currentCacheFile).Name;
                var songId = fileName.Substring(0, fileName.IndexOf("-"));
                var html = HttpHelper.SendGet("http://music.163.com/song?id=" + songId);
                if (html.Length > 0)
                {
                    var title = cut(html, "<title>", "</title>").Trim();
                    var tempFile = currentCacheFile+ Guid.NewGuid().ToString();
                    File.WriteAllBytes(tempFile, cacheFileData);
                    Track theTrack = new Track(tempFile);
                    // 父亲写的散文诗(时光版) - 许飞 - 单曲 - 网易云音乐
                    theTrack.Artist = cut(title, "-", "-").Trim();
                    theTrack.Title = title.Substring(0, title.IndexOf("-")).Trim();
                    // Save modifications on the disc
                    theTrack.Save();
                    cacheFileData = File.ReadAllBytes(tempFile);
                    File.Delete(tempFile);
    
                }
                
                return cacheFileData;
            }
    
        }
    

    接着介绍核心的Decryptor,实现转码的调度,这里的思路就是将所有的解码器放到一个list里,当一个文件过来的时候,遍历所有解码器,如果accetbale,就处理,否则跳过。
    两个主要工作:

    • 加载所有的BaseCacheDecrypt
    • 进行解码工作

    加载所有的BaseCacheDecrypt

    两种方法,一是自己实例化,一是使用反射,这里当然用反射了:)

    
    private Decryptor()
            {
               
            }
    
            public static Decryptor Instance
            {
                get
                {
                    return Holder.decryptor;
                }
            }
     static class Holder
            {
                public static Decryptor decryptor = Load();
    
    
                /// <summary>
                /// 从当前Assembly加载
                /// </summary>
                /// <returns></returns>
                private static Decryptor Load()
                {
                    Assembly assembly = Assembly.GetExecutingAssembly();
                    List<Type> hostTypes = new List<Type>();
    
                    foreach (var type in assembly.GetExportedTypes())
                    {
                        //确定type为类并且继承自(实现)IMyInstance
                        if (type.IsClass && typeof(BaseCacheDecrypt).IsAssignableFrom(type) && !type.IsAbstract)
                            hostTypes.Add(type);
                    }
    
                    Decryptor decryptor = new Decryptor();
                    foreach (var type in hostTypes)
                    {
                        ICacheDecrypt instance = (ICacheDecrypt)Activator.CreateInstance(type);
                        decryptor.cacheDecryptors.Add(instance);
                    }
    
                    return decryptor;
                }
            }
    

    Decryptor通过单例模式对外提供调用。

    进行解码

    判断拖入的是文件夹还是文件,文件夹的话遍历子文件,依次处理。解码方式就是钢说的,遍历decryptors,如果支持就解码。
    解码完后,读取ID3信息,对文件进行重命名。

     public int Process(string path)
            {
                int success = 0;
    
                if (Directory.Exists(path))//如果是文件夹
                {
                    DirectoryInfo dinfo = new DirectoryInfo(path);//实例化一个DirectoryInfo对象
                    foreach (FileInfo fs in dinfo.GetFiles()) //查找.kgtemp文件
                    {
                        ProcessFile(fs.FullName);
                        success++;
                    }
                }
                else
                {
                    ProcessFile(path);
                    success = 1;
                }
    
                return success;
            }
    
            private string GetCleanFileName(string fileName)
            {
                StringBuilder rBuilder = new StringBuilder(fileName);
                foreach (char rInvalidChar in Path.GetInvalidFileNameChars())
                    rBuilder.Replace(rInvalidChar.ToString(), string.Empty);
                return rBuilder.ToString();
            }
    
            private string GetTargetFileName(string fileName)
            {
                var fileinfo = new FileInfo(fileName);
                var rawName = fileinfo.Name.Substring(0, fileinfo.Name.IndexOf("."));
                return TargetDirectory + Path.DirectorySeparatorChar + rawName + ".mp3";
            }
    
    
            void ProcessFile(string fileName)
            {
                _logger.Info("开始处理" + fileName);
                try
                {
                    foreach (var decryptor in cacheDecryptors)
                    {
                        if (decryptor.isAcceptable(fileName))
                        {
                            var targetName = TargetDirectory + Path.DirectorySeparatorChar + new FileInfo(fileName).Name + ".mp3";
    
                            decryptor.Decrypt(fileName, targetName);
    
                            // 重命名
                            if (AutoRename)
                            {
                                var mp3 = ID3Helper.ReadMp3(targetName);
    
                                if (mp3.Title.Length > 0)
                                {
                                    string realFileName = GetTargetFileName(GetCleanFileName(mp3.Title + "-" + mp3.Artist + ".mp3"));
    
                                    _logger.Info("重命名" + realFileName);
                                    if (File.Exists(realFileName))
                                    {
                                        File.Delete(realFileName);
                                    }
    
                                    File.Move(targetName, realFileName);
                                }
                            }
                        }
                    }
                    _logger.Info(fileName + "处理完成");
                }
                catch(Exception ex)
                {
                    _logger.Error(fileName + "出现异常" + ex.Message);
                }
              
            }
    

    开源地址

    代码托管到了GitHub,musicDecryptor, 感兴趣的可以访问进行

    相关文章

      网友评论

          本文标题:开源小工具 酷狗、网易音乐缓存文件转mp3工具

          本文链接:https://www.haomeiwen.com/subject/wjwyfftx.html