提取Windows Media Player播放列表中的歌曲

前些日子买了个mp3,听着挺过瘾。在电脑上我都是用Windows Media Player播放歌曲,还把比较喜欢的“精选金曲”添加到了播放列表中。但想把播放列表中的歌曲拷到mp3里的时候却遇到了困难:列表中的歌曲分散在几十个专辑目录中,一个目录一个目录的找岂不要累死,这种重复性的机械劳动可是我最讨厌的了!好在咱还会写两行代码,看能不能用程序把这些歌曲提取出来。

好了,从分析Windows Media Player的播放列表入手。在Windows Media Player的音乐存储目录下我发现了一个“My Playlists”目录,里面有若干个.wpl文件。不管三七二十一,用记事本打开看看。结构如下:

<?wpl version="1.0"?>
<smil>
    <head>
        <meta name="Generator" content="Microsoft Windows Media Player -- 9.0.0.3128"/>
        <author/>
        <title>yFavorite</title>
    </head>
    <body>
        <seq>
            <media src="..\MovieMusic03\My Sassy Girl(我的野蛮女友)\02.I Believe.mp3" tid="{D5B723B4-A11F-4DE9-86C4-58A5803BE024}"/>
            <media src="..\MovieMusic03\My Sassy Girl(我的野蛮女友)\17.Episode 4 (Reg Time).mp3" tid="{79DE022B-0E10-464B-8E00-10FD3D200E1C}"/>
            <media src="..\MovieMusic04\天空の城\时间の城.mp3" tid="{D01404B4-0DB7-444E-AA06-28716F740D78}"/>
...(后面省略)

呵呵,这差不多就是xml文件啊,播放列表中所有歌曲的名字和路径都在里面,好办。

思路:把.wpl文件中从第二行开始的信息作为xml片断获得后,提取<media>节点的“src”属性值,再转换为绝对路径,然后复制到目标目录里。

设计界面如下:




主要方法:

        /// <summary>
        
/// 以DOM方式读取xml数据,复制文件,并以进度条控件显示执行进度。
        
/// </summary>

        private void CopySongsWithDoc( string wplFileName, string destDir )
        
{
            
string
 songName;
            
string songDir = wplFileName.Substring( 0, wplFileName.LastIndexOf( @""
 ) );

            XmlDocument xmlDoc 
= new
 XmlDocument();
            xmlDoc.LoadXml( 
this
.GetXmlFragment( wplFileName ) );

            XmlNodeList songsList 
= xmlDoc.GetElementsByTagName( "media"
 );
            
this.progressBar1.Maximum =
 songsList.Count;

            
foreach( XmlNode xn in
 songsList )
            
{
                
// 歌曲文件完整的绝对路径

                songName = this.RelativePathToAbsolutePath( xn.Attributes[ "src" ].Value, songDir );
                
                
if
( File.Exists( songName ) )
                    File.Copy( songName, destDir 
+ songName.Substring( songName.LastIndexOf( @"" ) ), true
 );

                
this.progressBar1.Value += 1
;
            }


            MessageBox.Show( 
"复制完成。" );
        }


        
/// <summary>
        
/// 把相对路径转换为绝对路径
        
/// </summary>

        
/// <param name="relativePath">相对路径</param>
        
/// <param name="currentDir">相对路径的当前目录</param>
        
/// <returns>对应的绝对路径</returns>

        private string RelativePathToAbsolutePath( string relativePath, string currentDir )
        
{
            
if( relativePath.IndexOf( ":" ) > 0 )    // 相对路径在另一个逻辑盘分区里,直接返回即可。

                return relativePath;
            
else

            
{
                
int lastSlashIndex = relativePath.LastIndexOf( @".."
 );
                
                
if( lastSlashIndex >= 0 )    // 如果从当前目录进入到相对路径所指示的目录需要先“向上”时

                {    
                    
// 相对路径中应该“向上”的目录层数,即“..”的个数

                    int upLayerCount = relativePath.Substring( 0, lastSlashIndex ).Split( new char[] '\' } ).Length;

                    
string[] sArray = currentDir.Split( new char[] '\' }
 );

                    
// 当前目录的层数

                    int currentDirLayerCount = sArray.Length;

                    
string dirAdded = ""
;
                    
if( currentDirLayerCount >
 upLayerCount )
                    
{
                        
//
 相对路径中每出现一次“..”,则 currentDir 就应该“向上”一级。
                        
// leftDirLayerCount 指 currentDir 中应该保留的目录层数。

                        int leftDirLayerCount = currentDirLayerCount - upLayerCount;

                        
forint i = 0; i < leftDirLayerCount; i++
 )
                        
{
                            dirAdded 
+= sArray[ i ] + @""
;
                        }

                    }

                    
return dirAdded + relativePath.Substring( lastSlashIndex + 3 );
                }

                
else    // 如果相对路径所指示的目录在当前目录内,但不在另一个逻辑盘分区里
                    return currentDir + @"" + relativePath;
            }

        }


        
/// <summary>
        
/// 从 WPL 文件中获取需要的 xml 片断。
        
/// </summary>

        
/// <param name="wplFileName">wpl文件名</param>
        
/// <returns>xml片断</returns>

        private string GetXmlFragment( string wplFileName )
        
{
            StreamReader sReader 
= new
 StreamReader( wplFileName, Encoding.UTF8 );
            
string xmlFragment =
 sReader.ReadToEnd();

            
// 把 wpl 文件的第一行去掉,从第二行开始取。

            xmlFragment = xmlFragment.Remove( 0, xmlFragment.IndexOf( @"<"1 ) );

            sReader.Close();
            
return
 xmlFragment;
        }



就这么简单,技术、方法都很初级,但自力更生的感觉还是很美妙的。 ^_^

posted on 2004-08-26 12:56  阳春三月  阅读(4284)  评论(10编辑  收藏  举报

导航