最近在处理一批下载的评书mp3文件时,需要把它们的一些属性做修改为有规律的样式,以便自己播放时知道是播放的那首。
要修改的属性如下:
修改的方法我是使用的 http://www.cnblogs.com/TianFang/archive/2009/09/27/1574722.html 介绍的 使用 WindowsAPICodePack 的方法来修改。
但是上述地址给出的函数有个小bug,且具体如何用代码实现也没有说明,所以整理了这篇博客,
WindowsAPICodePack 在下面地址可以下载:
http://code.msdn.microsoft.com/WindowsAPICodePack
我下载的是 Windows API Code Pack 1.0.1 中的
WindowsAPICodePack.zip
source code, 6927K, uploaded Nov 19
这个是源文件, 下载后打开可以看到 WindowsAPICodePack.sln 文件, 用 Visual Studio 编译后,我们可以得到下面2个文件:
Microsoft.WindowsAPICodePack.dll
Microsoft.WindowsAPICodePack.Shell.dll
这就是我们项目中要引用的两个文件。
引用这两个文件后,再在项目中增加一个文件,内容如下(注意把namespace修改为你自己的):
这个文件中也就是我说的http://www.cnblogs.com/TianFang/archive/2009/09/27/1574722.html 介绍的有小bug的文件,有错误的部分看下面我的注释。文件内容如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.WindowsAPICodePack.Shell; using Microsoft.WindowsAPICodePack.Shell.PropertySystem; using System.Reflection; namespace _52PS_WpfApplication { public class MediaTags { #region Mp3文件属性 /////// 标题 /// [MediaProperty("Title")] public string Title { get; set; } /// /// 子标题 /// [MediaProperty("Media.SubTitle")] public string SubTitle { get; set; } /// /// 星级 /// [MediaProperty("Rating")] public uint? Rating { get; set; } /// /// 备注 /// [MediaProperty("Comment")] public string Comment { get; set; } /// /// 艺术家 /// [MediaProperty("Author")] public string Author { get; set; } /// /// 唱片集 /// [MediaProperty("Music.AlbumTitle")] public string AlbumTitle { get; set; } /// /// 唱片集艺术家 /// [MediaProperty("Music.AlbumArtist")] public string AlbumArtist { get; set; } /// /// 年 /// [MediaProperty("Media.Year")] public uint? Year { get; set; } /// /// 流派 /// [MediaProperty("Music.Genre")] public string Genre { get; set; } /// /// # /// [MediaProperty("Music.TrackNumber")] public uint? TrackNumber { get; set; } /// /// 播放时间 /// [MediaProperty("Media.Duration")] public string Duration { get; private set; } /// /// 比特率 /// [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(PropertyDescriptionFormat.Default), 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; } // 这里做了修改 郭红俊 20091202 // 原先在旧值存在,新值没有给出时,会有空对象引用的bug //if (oldValue == null || !oldValue.Equals(newValue)) // 新的逻辑 新值存在时, 则替换旧值 if ((newValue != null) && (newValue.ToString().Trim().Length > 0) && (newValue != oldValue)) { var mp3Att = proper.GetCustomAttributes(typeof(MediaPropertyAttribute), false).FirstOrDefault(); var shellProper = mediaInfo.GetProperty("System." + mp3Att); Console.WriteLine(mp3Att); if (newValue == null) newValue = string.Empty; 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).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文件的标题属性,当然其他属性也是类似的。
private void btn_2_Click(object sender, RoutedEventArgs e) { MediaTags mt = new MediaTags(Environment.CurrentDirectory); for (int i = 1; i <= 16; i++) { string fileName = string.Format("{0}\\童林传_{1:000}.mp3", Environment.CurrentDirectory, i); mt.Title = string.Format("童林传 {0:000}",i); mt.Author = "单田芳"; mt.Commit(fileName); } }
参考资料:
用C#修改Mp3文件属性
http://www.cnblogs.com/TianFang/archive/2009/09/27/1574722.html