banshee r5072 - in trunk/banshee: . src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.Playlists.Formats src/Libraries/Mono.Media/Media.Playlists.Xspf



Author: gburt
Date: Thu Feb 26 20:23:09 2009
New Revision: 5072
URL: http://svn.gnome.org/viewvc/banshee?rev=5072&view=rev

Log:
2009-02-26  Gabriel Burt  <gabriel burt gmail com>

	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistParser.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/XspfPlaylistFormat.cs:
	* src/Core/Banshee.Services/Makefile.am:
	* src/Libraries/Mono.Media/Media.Playlists.Xspf/Playlist.cs:
	* src/Libraries/Mono.Media/Media.Playlists.Xspf/Track.cs:
	Patch from John Millikin adding support for importing and exporting XSPF
	playlist files (BGO #389537)

Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/XspfPlaylistFormat.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistParser.cs
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Playlist.cs
   trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Track.cs

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs	Thu Feb 26 20:23:09 2009
@@ -40,12 +40,14 @@
         
         private static PlaylistFormatDescription [] export_formats = new PlaylistFormatDescription [] {
             M3uPlaylistFormat.FormatDescription,
-            PlsPlaylistFormat.FormatDescription
+            PlsPlaylistFormat.FormatDescription,
+            XspfPlaylistFormat.FormatDescription
         };
         
         public static readonly string [] PlaylistExtensions = new string [] {
             M3uPlaylistFormat.FormatDescription.FileExtension,
-            PlsPlaylistFormat.FormatDescription.FileExtension
+            PlsPlaylistFormat.FormatDescription.FileExtension,
+            XspfPlaylistFormat.FormatDescription.FileExtension
         };
         
         public static PlaylistFormatDescription [] ExportFormats {
@@ -197,7 +199,7 @@
                     }
                     
                     ImportPlaylistWorker worker = new ImportPlaylistWorker (
-                        System.IO.Path.GetFileNameWithoutExtension (uri.LocalPath), 
+                        parser.Title, 
                         uris.ToArray (), source, importer);
                     worker.Import ();
                 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs	Thu Feb 26 20:23:09 2009
@@ -45,5 +45,6 @@
         List<Dictionary<string, object>> Elements { get; }
         
         Uri BaseUri { get; set; }
+        string Title { get; set; }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs	Thu Feb 26 20:23:09 2009
@@ -40,6 +40,7 @@
         private Dictionary<string, object> attributes = new Dictionary<string, object>();
         private List<Dictionary<string, object>> elements = new List<Dictionary<string, object>>();
         private Uri base_uri = new Uri(Environment.CurrentDirectory);
+        private string title = null;
         
         public PlaylistFormatBase()
         {
@@ -118,5 +119,10 @@
                 base_uri = value;
             }
         }
+        
+        public virtual string Title {
+            get { return title; }
+            set { title = value; }
+        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistParser.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistParser.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistParser.cs	Thu Feb 26 20:23:09 2009
@@ -41,11 +41,13 @@
         private static PlaylistFormatDescription [] playlist_formats = new PlaylistFormatDescription [] {
             M3uPlaylistFormat.FormatDescription,
             PlsPlaylistFormat.FormatDescription,
-            AsxPlaylistFormat.FormatDescription
+            AsxPlaylistFormat.FormatDescription,
+            XspfPlaylistFormat.FormatDescription
         };
         
         private List<Dictionary<string, object>> elements;
         private Uri base_uri = new Uri (Environment.CurrentDirectory);
+        private string title = null;
         
         public PlaylistParser ()
         {
@@ -134,6 +136,7 @@
                 stream.Dispose ();
                 
                 elements = playlist.Elements;
+                Title = playlist.Title ?? Path.GetFileNameWithoutExtension (uri.LocalPath);
                 return true;
             }
         }
@@ -146,5 +149,10 @@
             get { return base_uri; }
             set { base_uri = value; }
         }
+        
+        public string Title {
+            get { return title; }
+            set { title = value; }
+        }
     }
 }

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/XspfPlaylistFormat.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/XspfPlaylistFormat.cs	Thu Feb 26 20:23:09 2009
@@ -0,0 +1,92 @@
+//
+// XspfPlaylistFormat.cs
+//
+// Author:
+//   John Millikin <jmillikin gmail com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+using Mono.Unix;
+
+using Banshee.Collection;
+using Banshee.Sources;
+using Xspf = Media.Playlists.Xspf;
+ 
+namespace Banshee.Playlists.Formats
+{
+    public class XspfPlaylistFormat : PlaylistFormatBase
+    {
+        public static readonly PlaylistFormatDescription FormatDescription = new PlaylistFormatDescription (
+            typeof (XspfPlaylistFormat),
+            MagicHandler,
+            Catalog.GetString ("XML Shareable Playlist Format version 1 (*.xspf)"),
+            "xspf",
+            new string [] {"application/xspf+xml"}
+        );
+        
+        public static bool MagicHandler (StreamReader stream)
+        {
+            return Xspf.Playlist.Sniff (stream);
+        }
+        
+        public XspfPlaylistFormat ()
+        {
+        }
+        
+        public override void Load (StreamReader stream, bool validateHeader)
+        {
+            Xspf.Playlist playlist = new Xspf.Playlist ();
+            playlist.DefaultBaseUri = BaseUri;
+            playlist.Load (stream);
+            Title = playlist.Title;
+            foreach (Xspf.Track track in playlist.Tracks) {
+                Dictionary<string, object> element = AddElement ();
+                element["uri"] = track.GetLocationAt (0);
+            }
+        }
+        
+        public override void Save (Stream stream, ITrackModelSource source)
+        {
+            Xspf.Playlist playlist = new Xspf.Playlist ();
+            playlist.Title = source.Name;
+            playlist.Date = DateTime.Now;
+            for (int ii = 0; ii < source.TrackModel.Count; ii++) {
+                TrackInfo track = source.TrackModel[ii];
+                Xspf.Track xtrack = new Xspf.Track ();
+                xtrack.AddLocation (new Uri (ExportUri (track.Uri), UriKind.RelativeOrAbsolute));
+                xtrack.Title = track.TrackTitle;
+                xtrack.Creator = track.ArtistName;
+                xtrack.Album = track.AlbumTitle;
+                if (track.TrackNumber >= 0) {
+                    xtrack.TrackNumber = (uint)track.TrackNumber;
+                }
+                xtrack.Duration = track.Duration;
+                playlist.AddTrack (xtrack);
+            }
+            playlist.Save (stream);
+        }
+    }
+}
+// vi:tabstop=4:expandtab

Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am	Thu Feb 26 20:23:09 2009
@@ -132,6 +132,7 @@
 	Banshee.Playlists.Formats/PlaylistFormatDescription.cs \
 	Banshee.Playlists.Formats/PlaylistParser.cs \
 	Banshee.Playlists.Formats/PlsPlaylistFormat.cs \
+	Banshee.Playlists.Formats/XspfPlaylistFormat.cs \
 	Banshee.Playlists.Formats/Tests/PlaylistFormatTests.cs \
 	Banshee.Preferences/Collection.cs \
 	Banshee.Preferences/Page.cs \

Modified: trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Playlist.cs
==============================================================================
--- trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Playlist.cs	(original)
+++ trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Playlist.cs	Thu Feb 26 20:23:09 2009
@@ -56,22 +56,77 @@
         {
         }
         
-        private void Load(XmlDocument doc)
+        private static XmlNamespaceManager BuildNamespaceManager (XmlDocument doc)
+        {
+            XmlNamespaceManager xmlns = new XmlNamespaceManager (doc.NameTable);
+            xmlns.AddNamespace ("xspf", XspfNamespace);
+            return xmlns;
+        }
+        
+        private static XmlNode FindPlaylistNode (XmlDocument doc, XmlNamespaceManager xmlns)
+        {
+            XmlNode playlist_node = doc.SelectSingleNode ("/xspf:playlist", xmlns);
+            if (playlist_node == null) {
+                // Hack to work with files that don't have a namespace on the <playlist> node
+                xmlns.AddNamespace ("xspf", String.Empty);
+                playlist_node = doc.SelectSingleNode ("/xspf:playlist", xmlns);
+            }
+            return playlist_node;
+        }
+        
+        private static bool Sniff (XmlDocument doc)
         {
-            XmlNamespaceManager xmlns = new XmlNamespaceManager(doc.NameTable);
-            xmlns.AddNamespace("xspf", XspfNamespace);
+            XmlNamespaceManager xmlns = BuildNamespaceManager (doc);
+            XmlNode playlist_node = FindPlaylistNode (doc, xmlns);
             
-            XmlNode playlist_node = doc.SelectSingleNode("/xspf:playlist", xmlns);
-
-            if(playlist_node == null) {
-                // Hack to work with files that don't have a namespace on the <playlist> node, like Last.fm
-                xmlns.AddNamespace("xspf", String.Empty);
-                playlist_node = doc.SelectSingleNode("/xspf:playlist", xmlns);
-
-                if(playlist_node == null) {
-                    throw new ApplicationException("Not a valid XSPF playlist");
+            if (playlist_node != null) {
+                XmlAttribute version_attr = playlist_node.Attributes["version"];
+                if (!(version_attr == null || version_attr.Value == null)) {
+                    try {
+                        int version = Int32.Parse (version_attr.Value);
+                        if (version == 0 || version == 1) { return true; }
+                    } catch (FormatException) { }
                 }
             }
+            return false;
+        }
+        
+        public static bool Sniff (string path)
+        {
+            XmlDocument doc = new XmlDocument ();
+            doc.Load (path);
+            return Sniff (doc);
+        }
+        
+        public static bool Sniff (XmlReader reader)
+        {
+            XmlDocument doc = new XmlDocument ();
+            doc.Load (reader);
+            return Sniff (doc);
+        }
+        
+        public static bool Sniff (TextReader reader)
+        {
+            XmlDocument doc = new XmlDocument ();
+            doc.Load (reader);
+            return Sniff (doc);
+        }
+        
+        public static bool Sniff (Stream stream)
+        {
+            XmlDocument doc = new XmlDocument ();
+            doc.Load (stream);
+            return Sniff (doc);
+        }
+        
+        private void Load(XmlDocument doc)
+        {
+            XmlNamespaceManager xmlns = BuildNamespaceManager (doc);
+            XmlNode playlist_node = FindPlaylistNode (doc, xmlns);
+
+            if (playlist_node == null) {
+                throw new ApplicationException ("Not a valid XSPF playlist");
+            }
 
             XmlAttribute version_attr = playlist_node.Attributes["version"];
             if(version_attr == null || version_attr.Value == null) {
@@ -161,6 +216,10 @@
             
             SaveBase(writer);
             
+            if (Date.Ticks > 0) {
+                writer.WriteElementString ("date", Date.ToUniversalTime ().ToString ("o"));
+            }
+            
             writer.WriteStartElement("trackList");
             foreach(Track track in tracks) {
                 writer.WriteStartElement("track");

Modified: trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Track.cs
==============================================================================
--- trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Track.cs	(original)
+++ trunk/banshee/src/Libraries/Mono.Media/Media.Playlists.Xspf/Track.cs	Thu Feb 26 20:23:09 2009
@@ -89,8 +89,14 @@
                 writer.WriteElementString("album", album);
             }
             
+            // Only write valid (ie non-0) track numbers
+            if (TrackNumber > 0) {
+                writer.WriteElementString ("trackNum", TrackNumber.ToString ());
+            }
+            
             foreach(Uri uri in locations) {
-                writer.WriteElementString("location", uri.AbsoluteUri);
+                string escaped = uri.IsAbsoluteUri? uri.AbsoluteUri : Uri.EscapeUriString (uri.ToString ());
+                writer.WriteElementString ("location", escaped);
             }
         }
         



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]