朋友由于抠门 SD 卡买小了,结果音乐太多放不下,又不舍得再买新卡,不得已决定重新转码,把音乐码率压低一点,牺牲点音质来换空间(用某些人的话说,反正不是搞音乐的,听不出差别)…

结果千千静听(百度音乐)转码后会把音乐 ID3 信息里的标题当文件名…(PS:怀念当年的 千千静听…)

结果成了这个模样:

 

由于数量较多,收工改会死人的..

所以只好想办法用程序来批量改

找到了园友的老文章:http://www.cnblogs.com/TianFang/archive/2009/09/27/1574722.html

于是决定用 Windows API Code Pack

不过 MS 网站已经木有 Windows API Code Pack 的链接了

不过找起来也不麻烦

找到后新建工程,添加引用这两个 dll 就可以了

然后在工程里新建类 MediaTags,写入内容如下 :

    class MediaTags
    {
        #region Mp3文件属性
        /// <summary>
        /// 标题
        /// </summary>
        [MediaProperty("Title")]
        public string Title { get; set; }
 
        /// <summary>
        /// 子标题
        /// </summary>
        [MediaProperty("Media.SubTitle")]
        public string SubTitle { get; set; }
 
        /// <summary>
        /// 星级
        /// </summary>
        [MediaProperty("Rating")]
        public uint? Rating { get; set; }
 
        /// <summary>
        /// 备注
        /// </summary>
        [MediaProperty("Comment")]
        public string Comment { get; set; }
 
        /// <summary>
        /// 艺术家
        /// </summary>
        [MediaProperty("Author")]
        public string Author { get; set; }
 
        /// <summary>
        /// 唱片集
        /// </summary>
        [MediaProperty("Music.AlbumTitle")]
        public string AlbumTitle { get; set; }
 
        /// <summary>
        /// 唱片集艺术家
        /// </summary>
        [MediaProperty("Music.AlbumArtist")]
        public string AlbumArtist { get; set; }
 
        /// <summary>
        /// 年
        /// </summary>
        [MediaProperty("Media.Year")]
        public uint? Year { get; set; }
 
        /// <summary>
        /// 流派
        /// </summary>
        [MediaProperty("Music.Genre")]
        public string Genre { get; set; }
 
        /// <summary>
        /// #
        /// </summary>
        [MediaProperty("Music.TrackNumber")]
        public uint? TrackNumber { get; set; }
 
        /// <summary>
        /// 播放时间
        /// </summary>
        [MediaProperty("Media.Duration")]
        public string Duration { get; private set; }
 
        /// <summary>
        /// 比特率
        /// </summary>
        [MediaProperty("Audio.EncodingBitrate")]
        public string BitRate { get; private set; }
        #endregion
 
        public MediaTags(string mediaPath)
        {
            //var obj = ShellObject.FromParsingName(mp3Path);   //缩略图,只读
            //obj.Thumbnail.Bitmap.Save(@"R:\2.jpg");
 
            Init(mediaPath);
        }
 
        void Init(string mediaPath)
        {
            using (var obj = ShellObject.FromParsingName(mediaPath))
            {
                var mediaInfo = obj.Properties;
                foreach (var properItem in this.GetType().GetProperties())
                {
                    var mp3Att = properItem.GetCustomAttributes(typeof(MediaPropertyAttribute), false).FirstOrDefault();
                    var shellProper = mediaInfo.GetProperty("System." + mp3Att);
                    var value = shellProper == null ? null : shellProper.ValueAsObject;
 
                    if (value == null)
                    {
                        continue;
                    }
 
                    if (shellProper.ValueType == typeof(string[]))    //艺术家,流派等多值属性
                    {
                        properItem.SetValue(this, string.Join(";", value as string[]), null);
                    }
                    else if (properItem.PropertyType != shellProper.ValueType)    //一些只读属性,类型不是string,但作为string输出,避免转换 如播放时间,比特率等
                    {
                        properItem.SetValue(this, value == null ? "" : shellProper.FormatForDisplay(PropertyDescriptionFormatOptions.None), null);
                    }
                    else
                    {
                        properItem.SetValue(this, value, null);
                    }
                }
            }
        }
 
        public void Commit(string mp3Path)
        {
            var old = new MediaTags(mp3Path);
 
            using (var obj = ShellObject.FromParsingName(mp3Path))
            {
                var mediaInfo = obj.Properties;
                foreach (var proper in this.GetType().GetProperties())
                {
                    var oldValue = proper.GetValue(old, null);
                    var newValue = proper.GetValue(this, null);
 
                    if (oldValue == null && newValue == null)
                    {
                        continue;
                    }
 
                    if (oldValue == null || !oldValue.Equals(newValue))
                    {
                        var mp3Att = proper.GetCustomAttributes(typeof(MediaPropertyAttribute), false).FirstOrDefault();
                        var shellProper = mediaInfo.GetProperty("System." + mp3Att);
                        Console.WriteLine(mp3Att);
                        SetPropertyValue(shellProper, newValue);
                    }
                }
            }
        }
 
        #region SetPropertyValue
        static void SetPropertyValue(IShellProperty prop, object value)
        {
            if (prop.ValueType == typeof(string[]))        //只读属性不会改变,故与实际类型不符的只有string[]这一种
            {
                string[] values = (value as string).Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                (prop as ShellProperty<string[]>).Value = values;
            }
            if (prop.ValueType == typeof(string))
            {
                (prop as ShellProperty<string>).Value = value as string;
            }
            else if (prop.ValueType == typeof(ushort?))
            {
                (prop as ShellProperty<ushort?>).Value = value as ushort?;
            }
            else if (prop.ValueType == typeof(short?))
            {
                (prop as ShellProperty<short?>).Value = value as short?;
            }
            else if (prop.ValueType == typeof(uint?))
            {
                (prop as ShellProperty<uint?>).Value = value as uint?;
            }
            else if (prop.ValueType == typeof(int?))
            {
                (prop as ShellProperty<int?>).Value = value as int?;
            }
            else if (prop.ValueType == typeof(ulong?))
            {
                (prop as ShellProperty<ulong?>).Value = value as ulong?;
            }
            else if (prop.ValueType == typeof(long?))
            {
                (prop as ShellProperty<long?>).Value = value as long?;
            }
            else if (prop.ValueType == typeof(DateTime?))
            {
                (prop as ShellProperty<DateTime?>).Value = value as DateTime?;
            }
            else if (prop.ValueType == typeof(double?))
            {
                (prop as ShellProperty<double?>).Value = value as double?;
            }
        }
        #endregion
 
        #region MediaPropertyAttribute
        [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
        sealed class MediaPropertyAttribute : Attribute
        {
            public string PropertyKey { get; private set; }
            public MediaPropertyAttribute(string propertyKey)
            {
                this.PropertyKey = propertyKey;
            }
 
            public override string ToString()
            {
                return PropertyKey;
            }
        }
        #endregion
    }

剩下的就很简单了

读取当前文件夹下的所有mp3,批量替换标题

        static void Main(string[] args)
{
string fileDirectory = System.IO.Directory.GetCurrentDirectory();
DirectoryInfo folder = new DirectoryInfo(fileDirectory); foreach (FileInfo file in folder.GetFiles("*.mp3"))
{
MediaTags mt = new MediaTags(file.FullName);
mt.Title = file.FullName.Replace(fileDirectory + "\\", "").Replace(".mp3", "");
mt.Commit(file.FullName);
}
}

完成效果,剩下批量转换就可以了

利用 Windows API Code Pack 修改音乐的 ID3 信息的更多相关文章

  1. 关于Windows® API Code Pack for Microsoft® .NET Framework

    相比之前的操作系统,Window 7(or Vista)提供了很多新特性,我们在应用实现中可以利用这些特性来提升用户体验. 这些特性主要包括以下几个方面: Shell Enhancements Dir ...

  2. nodejs利用windows API读取文件属性(dll)

    nodejs调用delphi编写的dll中,使用了dll调用windows api转读取文件属性,感觉使用nodejs也可直接调用windows api. 此处需用到windows系统的version ...

  3. C#利用Windows API 实现关机、注销、重启等操作

    using System; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; nam ...

  4. 利用windows api共享内存通讯

    主要涉及CreateFile,CreateFileMapping,GetLastError,MapViewOfFile,sprintf,OpenFileMapping,CreateProcess Cr ...

  5. Windows API 进程相关笔记

    0. 前言 最近做了一个进程信息相关的项目,整理了一下自己做项目时的笔记,分享给大家 1. 相关概念 1.1 HANDLE 概念 HANDLE(句柄)是Windows操作系统中的一个概念. 在Wind ...

  6. Python调用Windows API函数编写录音机和音乐播放器

    功能描述: 1)使用tkinter设计程序界面: 2)调用Windows API函数实现录音机和音乐播放器. . 参考代码: ​ 运行界面: ​

  7. Windows API Hooking in Python

    catalogue . 相关基础知识 . Deviare API Hook Overview . 使用ctypes调用Windows API . pydbg . winappdbg . dll inj ...

  8. 逆向实用干货分享,Hook技术第一讲,之Hook Windows API

    逆向实用干货分享,Hook技术第一讲,之Hook Windows API 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) ...

  9. Windows API 函数列表 附帮助手册

    所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...

随机推荐

  1. fabric.js PatternBrush

    // Original canvas const canvas = new fabric.Canvas('canvas'); fabric.Image.fromURL('https://picsum. ...

  2. mutt+msmtp实现在shell环境中发送电子邮件

    作者:邓聪聪 为了自动化接收服务端的文件备份信息,利用mutt+msmtp在shell环境中发送电子邮件,轻松高效的完成运维工作. 下载msmtp wget http://downloads.sour ...

  3. Chromium Embedded Framework (CEF)_3.2171.2069_v20170606_x86.tar.xz

    CEF 为观看各个直播平台而特此修改的浏览器 可以单独提取 Flash 视频, 并可以修改视频的大小等功能 [增加了960x90% 和 1280x90%] 这次修改是主要针对 YY web 直播平台 ...

  4. CodeVs 3150 (大数 + 递推)

    #include<iostream> #include<cstdio> #include<cstring> #include<string> #incl ...

  5. Mysql 数据库安装与配置详解

    目录 一.概述 二.MySQL安装 三.安装成功验证 四.NavicatforMySQL下载及使用 一.概述 MySQL版本:5.7.17 下载地址:http://rj.baidu.com/soft/ ...

  6. [转]自定义alert弹框,title不显示域名

    //(仅去掉网址) (function(){ window.alert = function(name){ var iframe = document.createElement("IFRA ...

  7. Django 笔记(四)模板标签 ~ 自定义过滤器

    模板标签: 标签在渲染的过程中提供任意的逻辑 语法: 由{% ... %} 和 {% end... %} 常用标签: with:类似取别名 模版继承: Django模版引擎中最强大也是最复杂的部分就是 ...

  8. STM32L476应用开发之五:数据保存与SD卡操作

    便携式气体分析仪的特点就是离线运行.尽管是离线运行,但测试数据还是需要的,所以采取方式保存数据就是必须的.在本次项目中我们计划采用SD卡来保存数据. 1.硬件设计 该读卡器整合 SD 卡规范和 FAT ...

  9. selenium之 chromedriver与chrome版本映射表(更新至v2.33)

    看到网上基本没有最新的chromedriver与chrome的对应关系表,便兴起整理了一份如下,希望对大家有用: chromedriver版本 支持的Chrome版本 v2.33 v60-62 v2. ...

  10. 2。创建第一个angular应用,已经开发前的一些配置

    现在我们开始新建一个angular5的脚手架  . 到想要建项目的目录下.比如我的 在  D:\JsProjects 进入cmd或者powershell cd 进入该文件夹下 然后开始新建,ng ne ...